Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
730cf5e3
Commit
730cf5e3
authored
Apr 17, 2019
by
syasonik
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Unit tests and refactor for operability
parent
74daa11f
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
365 additions
and
0 deletions
+365
-0
lib/gitlab/metrics_dashboard/common_metrics_inserter.rb
lib/gitlab/metrics_dashboard/common_metrics_inserter.rb
+32
-0
lib/gitlab/metrics_dashboard/processor.rb
lib/gitlab/metrics_dashboard/processor.rb
+20
-0
lib/gitlab/metrics_dashboard/project_metrics_inserter.rb
lib/gitlab/metrics_dashboard/project_metrics_inserter.rb
+99
-0
lib/gitlab/metrics_dashboard/service.rb
lib/gitlab/metrics_dashboard/service.rb
+37
-0
lib/gitlab/metrics_dashboard/sorter.rb
lib/gitlab/metrics_dashboard/sorter.rb
+28
-0
spec/controllers/projects/environments_controller_spec.rb
spec/controllers/projects/environments_controller_spec.rb
+24
-0
spec/fixtures/lib/gitlab/metrics_dashboard/sample_dashboard.yml
...ixtures/lib/gitlab/metrics_dashboard/sample_dashboard.yml
+36
-0
spec/lib/gitlab/metrics_dashboard/processor_spec.rb
spec/lib/gitlab/metrics_dashboard/processor_spec.rb
+65
-0
spec/lib/gitlab/metrics_dashboard/service_spec.rb
spec/lib/gitlab/metrics_dashboard/service_spec.rb
+24
-0
No files found.
lib/gitlab/metrics_dashboard/common_metrics_inserter.rb
0 → 100644
View file @
730cf5e3
# frozen_string_literal: true
module
Gitlab
module
MetricsDashboard
class
CommonMetricsInserter
class
<<
self
# For each metric in the dashboard config, attempts to find a corresponding
# database record. If found, includes the record's id in the dashboard config.
def
transform!
(
dashboard
,
_project
)
common_metrics
=
::
PrometheusMetric
.
common
for_metrics
(
dashboard
)
do
|
metric
|
metric_record
=
common_metrics
.
find
{
|
m
|
m
.
identifier
==
metric
[
:id
]
}
metric
[
:metric_id
]
=
metric_record
.
id
if
metric_record
end
end
private
def
for_metrics
(
dashboard
)
dashboard
[
:panel_groups
].
each
do
|
panel_group
|
panel_group
[
:panels
].
each
do
|
panel
|
panel
[
:metrics
].
each
do
|
metric
|
yield
metric
end
end
end
end
end
end
end
end
lib/gitlab/metrics_dashboard/processor.rb
0 → 100644
View file @
730cf5e3
# frozen_string_literal: true
module
Gitlab
module
MetricsDashboard
class
Processor
STAGES
=
[
CommonMetricsInserter
,
ProjectMetricsInserter
,
Sorter
].
freeze
def
initialize
(
dashboard
,
project
)
@dashboard
=
dashboard
.
deep_transform_keys
(
&
:to_sym
)
@project
=
project
end
def
process
STAGES
.
each
{
|
stage
|
stage
.
transform!
(
@dashboard
,
@project
)
}
@dashboard
.
to_json
end
end
end
end
lib/gitlab/metrics_dashboard/project_metrics_inserter.rb
0 → 100644
View file @
730cf5e3
# frozen_string_literal: true
module
Gitlab
module
MetricsDashboard
class
ProjectMetricsInserter
DEFAULT_PANEL_TYPE
=
'area-chart'
class
<<
self
# Inserts project-specific metrics into the dashboard config.
# If there are no project-specific metrics, this will have no effect.
def
transform!
(
dashboard
,
project
)
project
.
prometheus_metrics
.
each
do
|
project_metric
|
group
=
find_or_create_panel_group
(
dashboard
[
:panel_groups
],
project_metric
)
panel
=
find_or_create_panel
(
group
[
:panels
],
project_metric
)
find_or_create_metric
(
panel
[
:metrics
],
project_metric
)
end
end
private
# Looks for a panel_group corresponding to the provided metric object.
# If unavailable, inserts one.
# @param panel_groups [Array<Hash>]
# @param metric [PrometheusMetric]
def
find_or_create_panel_group
(
panel_groups
,
metric
)
panel_group
=
find_panel_group
(
panel_groups
,
metric
)
return
panel_group
if
panel_group
panel_group
=
new_panel_group
(
metric
)
panel_groups
<<
panel_group
panel_group
end
# Looks for a panel corresponding to the provided metric object.
# If unavailable, inserts one.
# @param panels [Array<Hash>]
# @param metric [PrometheusMetric]
def
find_or_create_panel
(
panels
,
metric
)
panel
=
find_panel
(
panels
,
metric
)
return
panel
if
panel
panel
=
new_panel
(
metric
)
panels
<<
panel
panel
end
# Looks for a metric corresponding to the provided metric object.
# If unavailable, inserts one.
# @param metrics [Array<Hash>]
# @param metric [PrometheusMetric]
def
find_or_create_metric
(
metrics
,
metric
)
target_metric
=
find_metric
(
metrics
,
metric
)
return
target_metric
if
target_metric
target_metric
=
new_metric
(
metric
)
metrics
<<
target_metric
target_metric
end
def
find_panel_group
(
panel_groups
,
metric
)
panel_groups
.
find
{
|
group
|
group
[
:group
]
==
metric
.
group_title
}
end
def
find_panel
(
panels
,
metric
)
panel_identifiers
=
[
DEFAULT_PANEL_TYPE
,
metric
.
title
,
metric
.
y_label
]
panels
.
find
{
|
panel
|
panel
.
values_at
(
:type
,
:title
,
:y_label
)
==
panel_identifiers
}
end
def
find_metric
(
metrics
,
metric
)
metrics
.
find
{
|
m
|
m
[
:id
]
==
metric
.
identifier
}
end
def
new_panel_group
(
metric
)
{
group:
metric
.
group_title
,
priority:
metric
.
priority
,
panels:
[]
}
end
def
new_panel
(
metric
)
{
type:
DEFAULT_PANEL_TYPE
,
title:
metric
.
title
,
y_label:
metric
.
y_label
,
metrics:
[]
}
end
def
new_metric
(
metric
)
metric
.
queries
.
first
.
merge
(
metric_id:
metric
.
id
)
end
end
end
end
end
lib/gitlab/metrics_dashboard/service.rb
0 → 100644
View file @
730cf5e3
# frozen_string_literal: true
# Fetches the metrics dashboard layout and supplemented the output with DB info.
module
Gitlab
module
MetricsDashboard
class
Service
SYSTEM_DASHBOARD_NAME
=
'common_metrics'
SYSTEM_DASHBOARD_PATH
=
Rails
.
root
.
join
(
'config'
,
'prometheus'
,
"
#{
SYSTEM_DASHBOARD_NAME
}
.yml"
)
def
initialize
(
project
)
@project
=
project
end
# Returns a DB-supplemented json representation of a dashboard config file.
def
get_dashboard
dashboard
=
Rails
.
cache
.
fetch
(
cache_key
)
{
system_dashboard
}
process_dashboard
(
dashboard
)
end
private
# Returns the base metrics shipped with every GitLab service.
def
system_dashboard
YAML
.
load_file
(
SYSTEM_DASHBOARD_PATH
)
end
def
cache_key
"metrics_dashboard_
#{
SYSTEM_DASHBOARD_NAME
}
"
end
def
process_dashboard
(
dashboard
)
Processor
.
new
(
dashboard
,
@project
).
process
end
end
end
end
lib/gitlab/metrics_dashboard/sorter.rb
0 → 100644
View file @
730cf5e3
# frozen_string_literal: true
module
Gitlab
module
MetricsDashboard
class
Sorter
class
<<
self
def
transform!
(
dashboard
,
_project
)
sort_groups!
(
dashboard
)
sort_panels!
(
dashboard
)
end
private
# Sorts the groups in the dashboard by the :priority key
def
sort_groups!
(
dashboard
)
dashboard
[
:panel_groups
]
=
dashboard
[
:panel_groups
].
sort_by
{
|
group
|
-
group
[
:priority
].
to_i
}
end
# Sorts the panels in the dashboard by the :weight key
def
sort_panels!
(
dashboard
)
dashboard
[
:panel_groups
].
each
do
|
group
|
group
[
:panels
]
=
group
[
:panels
].
sort_by
{
|
panel
|
-
panel
[
:weight
].
to_i
}
end
end
end
end
end
end
spec/controllers/projects/environments_controller_spec.rb
View file @
730cf5e3
...
...
@@ -485,6 +485,30 @@ describe Projects::EnvironmentsController do
end
end
describe
'metrics_dashboard'
do
context
'when prometheus endpoint is disabled'
do
before
do
stub_feature_flags
(
environment_metrics_use_prometheus_endpoint:
false
)
end
it
'responds with status code 403'
do
get
:metrics_dashboard
,
params:
environment_params
(
format: :json
)
expect
(
response
).
to
have_gitlab_http_status
(
:forbidden
)
end
end
context
'when prometheus endpoint is enabled'
do
it
'returns a json representation of the environment dashboard'
do
get
:metrics_dashboard
,
params:
environment_params
(
format: :json
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
json_response
).
to
include
(
'dashboard'
,
'order'
,
'panel_groups'
)
expect
(
json_response
[
'panel_groups'
]).
to
all
(
include
(
'group'
,
'priority'
,
'panels'
)
)
end
end
end
describe
'GET #search'
do
before
do
create
(
:environment
,
name:
'staging'
,
project:
project
)
...
...
spec/fixtures/lib/gitlab/metrics_dashboard/sample_dashboard.yml
0 → 100644
View file @
730cf5e3
dashboard
:
'
Test
Dashboard'
order
:
1
panel_groups
:
-
group
:
Group A
priority
:
10
panels
:
-
title
:
"
Super
Chart
A1"
type
:
"
area-chart"
y_label
:
"
y_label"
weight
:
1
metrics
:
-
id
:
metric_a1
query_range
:
'
query'
unit
:
unit
label
:
Legend Label
-
title
:
"
Super
Chart
A2"
type
:
"
area-chart"
y_label
:
"
y_label"
weight
:
2
metrics
:
-
id
:
metric_a2
query_range
:
'
query'
label
:
Legend Label
unit
:
unit
-
group
:
Group B
priority
:
1
panels
:
-
title
:
"
Super
Chart
B"
type
:
"
area-chart"
y_label
:
"
y_label"
weight
:
1
metrics
:
-
id
:
metric_b
query_range
:
'
query'
unit
:
unit
label
:
Legend Label
spec/lib/gitlab/metrics_dashboard/processor_spec.rb
0 → 100644
View file @
730cf5e3
# frozen_string_literal: true
require
'spec_helper'
describe
Gitlab
::
MetricsDashboard
::
Processor
do
let
(
:project
)
{
build
(
:project
)
}
let
(
:dashboard_yml
)
{
YAML
.
load_file
(
'spec/fixtures/lib/gitlab/metrics_dashboard/sample_dashboard.yml'
)
}
describe
'process'
do
let
(
:dashboard
)
{
JSON
.
parse
(
described_class
.
new
(
dashboard_yml
,
project
).
process
,
symbolize_names:
true
)
}
context
'when dashboard config corresponds to common metrics'
do
let!
(
:common_metric
)
{
create
(
:prometheus_metric
,
:common
,
identifier:
'metric_a1'
)
}
it
'inserts metric ids into the config'
do
target_metric
=
all_metrics
.
find
{
|
metric
|
metric
[
:id
]
==
'metric_a1'
}
expect
(
target_metric
).
to
include
(
:metric_id
)
end
end
context
'when the project has associated metrics'
do
let!
(
:project_response_metric
)
{
create
(
:prometheus_metric
,
project:
project
,
group: :response
)
}
let!
(
:project_system_metric
)
{
create
(
:prometheus_metric
,
project:
project
,
group: :system
)
}
let!
(
:project_business_metric
)
{
create
(
:prometheus_metric
,
project:
project
,
group: :business
)
}
it
'includes project-specific metrics'
do
expect
(
all_metrics
).
to
include
get_metric_details
(
project_system_metric
)
expect
(
all_metrics
).
to
include
get_metric_details
(
project_response_metric
)
expect
(
all_metrics
).
to
include
get_metric_details
(
project_business_metric
)
end
it
'orders groups by priority and panels by weight'
do
expected_metrics_order
=
[
'metric_a2'
,
# group priority 10, panel weight 2
'metric_a1'
,
# group priority 10, panel weight 1
'metric_b'
,
# group priority 1, panel weight 1
project_business_metric
.
id
,
# group priority 0, panel weight nil (0)
project_response_metric
.
id
,
# group priority -5, panel weight nil (0)
project_system_metric
.
id
,
# group priority -10, panel weight nil (0)
]
actual_metrics_order
=
all_metrics
.
map
{
|
m
|
m
[
:id
]
||
m
[
:metric_id
]
}
expect
(
actual_metrics_order
).
to
eq
expected_metrics_order
end
end
end
private
def
all_metrics
dashboard
[
:panel_groups
].
map
do
|
group
|
group
[
:panels
].
map
{
|
panel
|
panel
[
:metrics
]
}
end
.
flatten
end
def
get_metric_details
(
metric
)
{
query_range:
metric
.
query
,
unit:
metric
.
unit
,
label:
metric
.
legend
,
metric_id:
metric
.
id
}
end
end
spec/lib/gitlab/metrics_dashboard/service_spec.rb
0 → 100644
View file @
730cf5e3
# frozen_string_literal: true
require
'spec_helper'
describe
Gitlab
::
MetricsDashboard
::
Service
,
:use_clean_rails_memory_store_caching
do
let
(
:project
)
{
build
(
:project
)
}
describe
'get_dashboard'
do
it
'returns a json representation of the environment dashboard'
do
dashboard
=
described_class
.
new
(
project
).
get_dashboard
json
=
JSON
.
parse
(
dashboard
,
symbolize_names:
true
)
expect
(
json
).
to
include
(
:dashboard
,
:order
,
:panel_groups
)
expect
(
json
[
:panel_groups
]).
to
all
(
include
(
:group
,
:priority
,
:panels
)
)
end
it
'caches the dashboard for subsequent calls'
do
expect
(
YAML
).
to
receive
(
:load_file
).
once
.
and_call_original
described_class
.
new
(
project
).
get_dashboard
described_class
.
new
(
project
).
get_dashboard
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment