Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Monitoring
Checkmk
Commits
03f8ac51
Commit
03f8ac51
authored
May 24, 2022
by
root
Browse files
Merge branch 'master' of
https://github.com/tribe29/checkmk
parents
1f397441
c38f80cb
Changes
9
Hide whitespace changes
Inline
Side-by-side
cmk/gui/plugins/metrics/artwork.py
View file @
03f8ac51
...
...
@@ -8,18 +8,41 @@ import math
import
time
from
functools
import
partial
from
itertools
import
zip_longest
from
typing
import
Callable
,
Iterable
,
List
,
Optional
,
Tuple
,
Union
from
typing
import
Any
,
Callable
,
Iterable
,
List
,
Optional
,
Sequence
,
Tuple
,
TypedDict
,
Union
import
cmk.utils.render
from
cmk.utils.prediction
import
TimeSeries
,
TimeSeriesValue
from
cmk.utils.type_defs
import
Seconds
,
Timestamp
from
cmk.gui.http
import
request
from
cmk.gui.i18n
import
_
from
cmk.gui.logged_in
import
user
from
cmk.gui.plugins.metrics
import
rrd_fetch
,
timeseries
from
cmk.gui.plugins.metrics.utils
import
unit_info
from
cmk.gui.plugins.metrics.utils
import
(
Curve
,
GraphArtwork
,
GraphDataRange
,
GraphRecipe
,
GraphRenderOptions
,
SizeEx
,
unit_info
,
UnitInfo
,
)
from
cmk.gui.type_defs
import
UnitRenderFunc
from
cmk.gui.utils.theme
import
theme
Label
=
Tuple
[
int
,
Optional
[
str
],
int
]
Label
=
Tuple
[
float
,
Optional
[
str
],
int
]
LayoutedCurve
=
dict
[
str
,
Any
]
VerticalAxis
=
dict
[
str
,
Any
]
TimeAxis
=
dict
[
str
,
Any
]
class
CurveValue
(
TypedDict
):
title
:
str
color
:
str
rendered_value
:
tuple
[
TimeSeriesValue
,
str
]
# .--Default Render Options----------------------------------------------.
# | ____ _ |
...
...
@@ -37,7 +60,7 @@ Label = Tuple[int, Optional[str], int]
# '----------------------------------------------------------------------'
def
get_default_graph_render_options
():
def
get_default_graph_render_options
()
->
GraphRenderOptions
:
return
{
"font_size"
:
8.0
,
# pt
"resizable"
:
True
,
...
...
@@ -62,29 +85,43 @@ def get_default_graph_render_options():
}
def
_graph_colors
(
theme_id
):
class
GraphColors
(
TypedDict
):
background_color
:
Optional
[
str
]
foreground_color
:
Optional
[
str
]
canvas_color
:
Optional
[
str
]
def
_graph_colors
(
theme_id
:
str
)
->
GraphColors
:
return
{
"modern-dark"
:
{
"background_color"
:
None
,
"foreground_color"
:
"#ffffff"
,
"canvas_color"
:
None
,
},
"pdf"
:
{
"background_color"
:
"#f8f4f0"
,
"foreground_color"
:
"#000000"
,
"canvas_color"
:
"#ffffff"
,
},
"modern-dark"
:
GraphColors
(
{
"background_color"
:
None
,
"foreground_color"
:
"#ffffff"
,
"canvas_color"
:
None
,
}
),
"pdf"
:
GraphColors
(
{
"background_color"
:
"#f8f4f0"
,
"foreground_color"
:
"#000000"
,
"canvas_color"
:
"#ffffff"
,
}
),
}.
get
(
theme_id
,
{
"background_color"
:
None
,
"foreground_color"
:
"#000000"
,
"canvas_color"
:
None
,
},
GraphColors
(
{
"background_color"
:
None
,
"foreground_color"
:
"#000000"
,
"canvas_color"
:
None
,
}
),
)
def
add_default_render_options
(
graph_render_options
,
render_unthemed
=
False
):
def
add_default_render_options
(
graph_render_options
:
GraphRenderOptions
,
render_unthemed
:
bool
=
False
)
->
GraphRenderOptions
:
options
=
get_default_graph_render_options
()
options
.
update
(
graph_render_options
)
options
.
setdefault
(
"size"
,
user
.
load_file
(
"graph_size"
,
(
70
,
16
)))
...
...
@@ -112,7 +149,11 @@ def add_default_render_options(graph_render_options, render_unthemed=False):
# '----------------------------------------------------------------------'
def
compute_graph_artwork
(
graph_recipe
,
graph_data_range
,
graph_render_options
):
def
compute_graph_artwork
(
graph_recipe
:
GraphRecipe
,
graph_data_range
:
GraphDataRange
,
graph_render_options
:
GraphRenderOptions
,
)
->
GraphArtwork
:
graph_render_options
=
add_default_render_options
(
graph_render_options
)
curves
=
compute_graph_artwork_curves
(
graph_recipe
,
graph_data_range
)
...
...
@@ -173,7 +214,7 @@ def compute_graph_artwork(graph_recipe, graph_data_range, graph_render_options):
# Compute the location of the curves of the graph, implement
# stacking and mirroring (displaying positive values in negative
# direction).
def
layout_graph_curves
(
curves
)
:
def
layout_graph_curves
(
curves
:
Sequence
[
Curve
])
->
tuple
[
list
[
LayoutedCurve
],
bool
]
:
mirrored
=
False
# True if negative area shows positive values
# Build positive and optional negative stack.
...
...
@@ -184,7 +225,7 @@ def layout_graph_curves(curves):
# For areas we put (lower, higher) as point into the list of points.
# For lines simply the values. For mirrored values from is >= to.
def
mirror_point
(
p
)
:
def
mirror_point
(
p
:
Optional
[
int
])
->
Optional
[
int
]
:
if
p
is
None
:
return
p
return
-
p
...
...
@@ -258,7 +299,9 @@ def areastack(raw_points, base):
return
list
(
map
(
fix_swap
,
zip_longest
(
base
,
edge
)))
def
compute_graph_artwork_curves
(
graph_recipe
,
graph_data_range
):
def
compute_graph_artwork_curves
(
graph_recipe
:
GraphRecipe
,
graph_data_range
:
GraphDataRange
)
->
list
[
Curve
]:
# Fetch all raw RRD data
rrd_data
=
rrd_fetch
.
fetch_rrd_data_for_graph
(
graph_recipe
,
graph_data_range
)
...
...
@@ -306,7 +349,9 @@ def halfstep_interpolation(rrddata):
# '----------------------------------------------------------------------'
def
_compute_scalars
(
graph_recipe
,
curves
,
pin_time
):
def
_compute_scalars
(
graph_recipe
:
GraphRecipe
,
curves
:
Sequence
[
Curve
],
pin_time
:
Optional
[
int
]
)
->
None
:
unit
=
unit_info
[
graph_recipe
[
"unit"
]]
for
curve
in
curves
:
...
...
@@ -337,7 +382,9 @@ def _compute_scalars(graph_recipe, curves, pin_time):
curve
[
"scalars"
][
key
]
=
_render_scalar_value
(
value
,
unit
)
def
_compute_curve_values_at_timestamp
(
graph_recipe
,
curves
,
hover_time
):
def
_compute_curve_values_at_timestamp
(
graph_recipe
:
GraphRecipe
,
curves
:
Sequence
[
Curve
],
hover_time
:
int
)
->
list
[
CurveValue
]:
unit
=
unit_info
[
graph_recipe
[
"unit"
]]
curve_values
=
[]
...
...
@@ -350,23 +397,25 @@ def _compute_curve_values_at_timestamp(graph_recipe, curves, hover_time):
value
=
_get_value_at_timestamp
(
hover_time
,
rrddata
)
curve_values
.
append
(
{
"title"
:
curve
[
"title"
],
"color"
:
curve
[
"color"
],
"rendered_value"
:
_render_scalar_value
(
value
,
unit
),
}
CurveValue
(
{
"title"
:
curve
[
"title"
],
"color"
:
curve
[
"color"
],
"rendered_value"
:
_render_scalar_value
(
value
,
unit
),
}
)
)
return
curve_values
def
_render_scalar_value
(
value
,
unit
):
def
_render_scalar_value
(
value
,
unit
)
->
tuple
[
TimeSeriesValue
,
str
]
:
if
value
is
None
:
return
None
,
_
(
"n/a"
)
return
value
,
unit
[
"render"
](
value
)
def
_get_value_at_timestamp
(
pin_time
,
rrddata
)
:
def
_get_value_at_timestamp
(
pin_time
:
int
,
rrddata
:
TimeSeries
)
->
TimeSeriesValue
:
start_time
,
_
,
step
=
rrddata
.
twindow
nth_value
=
(
pin_time
-
start_time
)
//
step
if
0
<=
nth_value
<
len
(
rrddata
):
...
...
@@ -394,7 +443,13 @@ def _get_value_at_timestamp(pin_time, rrddata):
# without a - sign.
#
# height -> Graph area height in ex
def
compute_graph_v_axis
(
graph_recipe
,
graph_data_range
,
height_ex
,
layouted_curves
,
mirrored
):
def
compute_graph_v_axis
(
graph_recipe
:
GraphRecipe
,
graph_data_range
:
GraphDataRange
,
height_ex
:
SizeEx
,
layouted_curves
:
Sequence
[
LayoutedCurve
],
mirrored
:
bool
,
)
->
VerticalAxis
:
unit
=
unit_info
[
graph_recipe
[
"unit"
]]
# Calculate the the value range
...
...
@@ -475,28 +530,37 @@ def compute_graph_v_axis(graph_recipe, graph_data_range, height_ex, layouted_cur
# strange things can happen due to internal precision limitation.
# Here we compute the number of decimal digits we need
# Adds "labels", "max_label_length" and updates "axis_label" in case
# of units which use a graph global unit
rendered_labels
,
max_label_length
,
graph_unit
=
create_vertical_axis_labels
(
min_value
,
max_value
,
unit
,
label_distance
,
sub_distance
,
mirrored
)
v_axis
=
{
"range"
:
(
min_value
,
max_value
),
"real_range"
:
real_range
,
"label_distance"
:
label_distance
,
"sub_distance"
:
sub_distance
,
"axis_label"
:
None
,
"rendered_labels"
:
rendered_labels
,
"max_label_length"
:
max_label_length
,
}
# Adds "labels", "max_label_length" and updates "axis_label" in case
# of units which use a graph global unit
v_axis
.
update
(
create_vertical_axis_labels
(
min_value
,
max_value
,
unit
,
label_distance
,
sub_distance
,
mirrored
)
)
return
v_axis
if
graph_unit
is
not
None
:
v_axis
[
"graph_unit"
]
=
graph_unit
return
v_axis
def
compute_v_axis_min_max
(
graph_recipe
,
graph_data_range
,
height
,
layouted_curves
,
mirrored
):
min_value
,
max_value
=
_get_min_max_from_curves
(
layouted_curves
)
min_value
,
max_value
=
_purge_min_max
(
min_value
,
max_value
,
mirrored
)
def
compute_v_axis_min_max
(
graph_recipe
:
GraphRecipe
,
graph_data_range
:
GraphDataRange
,
height
:
SizeEx
,
layouted_curves
:
Sequence
[
LayoutedCurve
],
mirrored
:
bool
,
)
->
tuple
[
tuple
[
float
,
float
],
float
,
float
,
float
]:
opt_min_value
,
opt_max_value
=
_get_min_max_from_curves
(
layouted_curves
)
min_value
,
max_value
=
_purge_min_max
(
opt_min_value
,
opt_max_value
,
mirrored
)
# Apply explicit range if defined in graph
explicit_min_value
,
explicit_max_value
=
graph_recipe
[
"explicit_vertical_range"
]
...
...
@@ -544,7 +608,9 @@ def compute_v_axis_min_max(graph_recipe, graph_data_range, height, layouted_curv
return
real_range
,
vrange
,
min_value
,
max_value
def
_purge_min_max
(
min_value
,
max_value
,
mirrored
):
def
_purge_min_max
(
min_value
:
Optional
[
float
],
max_value
:
Optional
[
float
],
mirrored
:
bool
)
->
tuple
[
float
,
float
]:
# If all of our data points are None, then we have no
# min/max values. In this case we assume 0 as a minimum
# value and 1 as a maximum. Otherwise we will run into
...
...
@@ -552,25 +618,35 @@ def _purge_min_max(min_value, max_value, mirrored):
if
min_value
is
None
and
max_value
is
None
:
min_value
=
-
1.0
if
mirrored
else
0.0
max_value
=
1.0
return
min_value
,
max_value
el
if
min_value
is
None
and
max_value
>
0
:
min_value
=
-
1
*
max_value
if
mirrored
else
0.0
elif
max_value
is
None
and
min_value
<
0
:
max_value
=
1.0
if
min_value
is
None
and
max_value
is
not
None
:
if
max_value
>
0
:
min_value
=
-
1
*
max_value
if
mirrored
else
0.0
return
min_value
,
max_value
elif
min_value
is
None
and
max_value
is
not
None
:
if
mirrored
:
min_value
=
-
1
*
max_value
else
:
min_value
=
max_value
-
1.0
return
min_value
,
max_value
if
max_value
is
None
and
min_value
is
not
None
:
if
min_value
<
0
:
max_value
=
1.0
return
min_value
,
max_value
elif
max_value
is
None
and
min_value
is
not
None
:
max_value
=
min_value
+
1.0
return
min_value
,
max_value
assert
min_value
is
not
None
assert
max_value
is
not
None
return
min_value
,
max_value
def
_get_min_max_from_curves
(
layouted_curves
):
def
_get_min_max_from_curves
(
layouted_curves
:
Sequence
[
LayoutedCurve
],
)
->
tuple
[
Optional
[
float
],
Optional
[
float
]]:
min_value
,
max_value
=
None
,
None
# Now make sure that all points are within the range.
...
...
@@ -608,7 +684,14 @@ def _get_min_max_from_curves(layouted_curves):
# Create labels for the neccessary range
def
create_vertical_axis_labels
(
min_value
,
max_value
,
unit
,
label_distance
,
sub_distance
,
mirrored
):
def
create_vertical_axis_labels
(
min_value
:
float
,
max_value
:
float
,
unit
:
UnitInfo
,
label_distance
:
float
,
sub_distance
:
float
,
mirrored
:
bool
,
)
->
tuple
[
list
[
Label
],
int
,
Optional
[
str
]]:
# round_to is the precision (number of digits after the decimal point)
# that we round labels to.
round_to
=
max
(
0
,
3
-
math
.
trunc
(
math
.
log10
(
max
(
abs
(
min_value
),
abs
(
max_value
)))))
...
...
@@ -655,32 +738,42 @@ def create_vertical_axis_labels(min_value, max_value, unit, label_distance, sub_
return
render_labels_with_graph_unit
(
label_specs
,
unit
)
def
render_labels_with_individual_units
(
label_specs
,
unit
):
return
render_labels
(
label_specs
,
unit
[
"render"
])
def
render_labels_with_individual_units
(
label_specs
:
Sequence
[
tuple
[
float
,
Optional
[
float
],
int
]],
unit
:
UnitInfo
)
->
tuple
[
list
[
Label
],
int
,
None
]:
rendered_labels
,
max_label_length
=
render_labels
(
label_specs
,
unit
[
"render"
])
return
rendered_labels
,
max_label_length
,
None
def
render_labels_with_graph_unit
(
label_specs
,
unit
):
def
render_labels_with_graph_unit
(
label_specs
:
Sequence
[
tuple
[
float
,
Optional
[
float
],
int
]],
unit
:
UnitInfo
)
->
tuple
[
list
[
Label
],
int
,
str
]:
# Build list of real values (not 0 or None) for the graph_unit function
# which is then calculating the graph global unit
ignored_values
=
[
0
,
None
]
ignored_values
=
(
0
,
None
)
values
=
[
l
[
1
]
for
l
in
label_specs
if
l
[
1
]
not
in
ignored_values
]
values
=
[
l
[
1
]
for
l
in
label_specs
if
l
[
1
]
is
not
None
and
l
[
1
]
not
in
ignored_values
]
graph_unit
,
scaled_labels
=
unit
[
"graph_unit"
](
values
)
scaled_label_specs
:
list
[
tuple
[
float
,
Union
[
None
,
str
,
float
],
int
]]
=
[]
# Merge the scaled labels into the label specifications
for
index
,
label_spec
in
enumerate
(
label_specs
):
if
label_spec
[
1
]
not
in
ignored_values
:
label_specs
[
index
]
=
(
label_spec
[
0
],
scaled_labels
.
pop
(
0
),
label_spec
[
2
])
scaled_label_specs
[
index
]
=
(
label_spec
[
0
],
scaled_labels
.
pop
(
0
),
label_spec
[
2
])
else
:
scaled_label_specs
[
index
]
=
(
label_spec
[
0
],
label_spec
[
1
],
label_spec
[
2
])
v_axis_attributes
=
render_labels
(
label_specs
)
v_axis_attributes
[
"axis_label"
]
=
graph_unit
return
v_axis_attributes
rendered_labels
,
max_label_length
=
render_labels
(
scaled_label_specs
)
return
rendered_labels
,
max_label_length
,
graph_unit
def
render_labels
(
label_specs
,
render_func
=
None
):
def
render_labels
(
label_specs
:
Sequence
[
tuple
[
float
,
Union
[
None
,
str
,
float
],
int
]],
render_func
:
Optional
[
UnitRenderFunc
]
=
None
,
)
->
tuple
[
list
[
Label
],
int
]:
max_label_length
=
0
rendered_labels
:
L
ist
[
Label
]
=
[]
rendered_labels
:
l
ist
[
Label
]
=
[]
for
pos
,
label_value
,
line_width
in
label_specs
:
if
label_value
is
not
None
:
...
...
@@ -690,7 +783,7 @@ def render_labels(label_specs, render_func=None):
if
render_func
:
label
=
render_func
(
label_value
)
else
:
label
=
"%s"
%
label_value
label
=
str
(
label_value
)
# Generally remove useless zeroes in fixed point numbers.
# This is a bit hacky. Got no idea how to make this better...
...
...
@@ -701,13 +794,10 @@ def render_labels(label_specs, render_func=None):
else
:
rendered_labels
.
append
((
pos
,
None
,
line_width
))
return
{
"labels"
:
rendered_labels
,
"max_label_length"
:
max_label_length
,
}
return
rendered_labels
,
max_label_length
def
remove_useless_zeroes
(
label
)
:
def
remove_useless_zeroes
(
label
:
str
)
->
str
:
if
"."
not
in
label
:
return
label
...
...
@@ -727,7 +817,9 @@ def remove_useless_zeroes(label):
# '----------------------------------------------------------------------'
def
compute_graph_t_axis
(
start_time
,
end_time
,
width
,
step
):
def
compute_graph_t_axis
(
start_time
:
Timestamp
,
end_time
:
Timestamp
,
width
:
int
,
step
:
Seconds
)
->
TimeAxis
:
# Depending on which time range is being shown we have different
# steps of granularity
...
...
@@ -747,7 +839,7 @@ def compute_graph_t_axis(start_time, end_time, width, step):
time_range_days
=
time_range
/
86400
label_shift
=
0
# shift seconds to future in order to center it
label_distance_at_least
=
0
label_distance_at_least
=
0
.0
if
start_date
==
end_date
:
title_label
=
str
(
cmk
.
utils
.
render
.
date
(
start_time
))
else
:
...
...
@@ -811,7 +903,7 @@ def compute_graph_t_axis(start_time, end_time, width, step):
(
5760
,
720
),
]:
if
label_distance_at_least
<=
dist_minutes
*
60
:
dist_function
:
Callable
[[
int
,
int
],
Iterable
[
Tuple
[
in
t
,
int
,
bool
]]]
=
partial
(
dist_function
:
Callable
[[
int
,
int
],
Iterable
[
Tuple
[
floa
t
,
int
,
bool
]]]
=
partial
(
dist_equal
,
distance
=
dist_minutes
*
60
,
subdivision
=
subdivision
*
60
)
break
...
...
@@ -863,14 +955,14 @@ def compute_graph_t_axis(start_time, end_time, width, step):
}
def
add_step_to_title
(
title_label
,
step
)
:
def
add_step_to_title
(
title_label
:
str
,
step
:
Seconds
)
->
str
:
step_label
=
get_step_label
(
step
)
if
title_label
is
None
:
return
step_label
return
"%s @ %s"
%
(
title_label
,
step_label
)
def
get_step_label
(
step
)
:
def
get_step_label
(
step
:
Seconds
)
->
str
:
if
step
<
3600
:
return
"%dm"
%
(
step
/
60
)
if
step
<
86400
:
...
...
@@ -878,7 +970,7 @@ def get_step_label(step):
return
"%dd"
%
(
step
/
86400
)
def
dist_week
(
start_time
,
end_time
)
:
def
dist_week
(
start_time
:
int
,
end_time
:
int
)
->
Iterable
[
tuple
[
float
,
int
,
bool
]]
:
# Shift time back to monday
wday_of_start_time
=
time
.
localtime
(
start_time
).
tm_wday
monday_week
=
start_time
-
86400
*
wday_of_start_time
...
...
@@ -889,7 +981,7 @@ def dist_week(start_time, end_time):
yield
(
pos
,
line_width
,
has_label
)
def
dist_month
(
start_time
,
end_time
,
months
)
:
def
dist_month
(
start_time
:
int
,
end_time
:
int
,
months
:
int
)
->
Iterable
[
tuple
[
float
,
int
,
bool
]]
:
# Jump to beginning of month
broken
=
time
.
localtime
(
start_time
)
broken_tm_year
=
broken
[
0
]
...
...
@@ -950,7 +1042,9 @@ def dist_month(start_time, end_time, months):
# labels. These points have the label (None). The function
# returns tuples of the form (time, line), where
# line is one of 0, 1, 2 (none, thin, thick)
def
dist_equal
(
start_time
,
end_time
,
distance
,
subdivision
):
def
dist_equal
(
start_time
:
int
,
end_time
:
int
,
distance
:
int
,
subdivision
:
float
)
->
Iterable
[
tuple
[
float
,
int
,
bool
]]:
# First align start_time to the next time that can be divided
# distance, but align this at 00:00 localtime!
align_broken
=
time
.
localtime
(
start_time
)
...
...
@@ -996,7 +1090,7 @@ def dist_equal(start_time, end_time, distance, subdivision):
# '----------------------------------------------------------------------'
def
load_graph_pin
():
def
load_graph_pin
()
->
Optional
[
int
]
:
return
user
.
load_file
(
"graph_pin"
,
None
)
...
...
cmk/gui/plugins/metrics/graph_images.py
View file @
03f8ac51
...
...
@@ -10,11 +10,13 @@ import base64
import
json
import
time
import
traceback
from
typing
import
Any
,
Optional
import
livestatus
import
cmk.utils
import
cmk.utils.render
from
cmk.utils.type_defs
import
Timestamp
import
cmk.gui.pdf
as
pdf
from
cmk.gui.config
import
active_config
...
...
@@ -24,6 +26,7 @@ from cmk.gui.i18n import _
from
cmk.gui.log
import
logger
from
cmk.gui.logged_in
import
SuperUserContext
from
cmk.gui.plugins.metrics
import
artwork
,
html_render
from
cmk.gui.plugins.metrics.artwork
import
GraphArtwork
,
GraphDataRange
,
GraphRenderOptions
from
cmk.gui.plugins.metrics.graph_pdf
import
(
compute_pdf_graph_data_range
,
get_mm_per_ex
,
...
...
@@ -31,14 +34,14 @@ from cmk.gui.plugins.metrics.graph_pdf import (
render_graph_pdf
,
)
from
cmk.gui.plugins.metrics.identification
import
graph_identification_types
from
cmk.gui.plugins.metrics.utils
import
get_graph_data_from_livestatus
from
cmk.gui.plugins.metrics.utils
import
get_graph_data_from_livestatus
,
GraphRecipe
# Provides a json list containing base64 encoded PNG images of the current 24h graphs
# of a host or service.
# # Needed by mail notification plugin (-> no authentication from localhost)
@
cmk
.
gui
.
pages
.
register
(
"noauth:ajax_graph_images"
)
def
ajax_graph_images_for_notifications
():
def
ajax_graph_images_for_notifications
()
->
None
:
if
request
.
remote_ip
not
in
[
"127.0.0.1"
,
"::1"
]:
raise
MKUnauthenticatedException
(
_
(
"You are not allowed to access this page (%s)."
)
%
request
.
remote_ip
...
...
@@ -74,7 +77,7 @@ def _answer_graph_image_request() -> None:
site
=
row
[
"site"
]
# Always use 25h graph in notifications
end_time
=
time
.
time
()
end_time
=
int
(
time
.
time
()
)
start_time
=
end_time
-
(
25
*
3600
)
graph_render_options
=
graph_image_render_options
()
...
...
@@ -112,13 +115,15 @@ def _answer_graph_image_request() -> None:
raise
def
graph_image_data_range
(
graph_render_options
,
start_time
,
end_time
):
def
graph_image_data_range
(
graph_render_options
:
GraphRenderOptions
,
start_time
:
Timestamp
,
end_time
:
Timestamp
)
->
GraphDataRange
:
mm_per_ex
=
get_mm_per_ex
(
graph_render_options
[
"font_size"
])
width_mm
=
graph_render_options
[
"size"
][
0
]
*
mm_per_ex
return
compute_pdf_graph_data_range
(
width_mm
,
start_time
,
end_time
)
def
graph_image_render_options
(
api_request
=
None
)
:
def
graph_image_render_options
(
api_request
:
Optional
[
dict
[
str
,
Any
]]
=
None
)
->
GraphRenderOptions
:
# Set image rendering defaults
graph_render_options
=
{
"font_size"
:
8.0
,
# pt
...
...
@@ -145,7 +150,11 @@ def graph_image_render_options(api_request=None):
return
graph_render_options
def
render_graph_image
(
graph_artwork
,
graph_data_range
,
graph_render_options
):
def
render_graph_image
(
graph_artwork
:
GraphArtwork
,
graph_data_range
:
GraphDataRange
,
graph_render_options
:
GraphRenderOptions
,
)
->
bytes
:
width_ex
,
height_ex
=
graph_render_options
[
"size"
]
mm_per_ex
=
get_mm_per_ex
(
graph_render_options
[
"font_size"
])
...
...
@@ -186,7 +195,9 @@ def render_graph_image(graph_artwork, graph_data_range, graph_render_options):
return
pdf
.
pdf2png
(
pdf_graph
)
def
graph_recipes_for_api_request
(
api_request
):
def
graph_recipes_for_api_request
(
api_request
:
dict
[
str
,
Any
]
)
->
tuple
[
GraphDataRange
,
list
[
GraphRecipe
]]:
# Get and validate the specification
graph_identification
=
api_request
.
get
(
"specification"
,
[])
if
not
graph_identification
:
...
...
@@ -201,7 +212,7 @@ def graph_recipes_for_api_request(api_request):
default_time_range
=
(
time
.
time
()
-
(
25
*
3600
),
time
.
time
())
# Get and validate the data range
graph_data_range
=
api_request
.
get
(
"data_range"
,
{})
graph_data_range
:
GraphDataRange
=
api_request
.
get
(
"data_range"
,
{})
graph_data_range
.
setdefault
(
"time_range"
,
default_time_range
)
time_range
=
graph_data_range
[
"time_range"
]
...
...
@@ -232,7 +243,7 @@ def graph_recipes_for_api_request(api_request):
return
graph_data_range
,
graph_recipes
def
graph_spec_from_request
(
api_request
)
:
def
graph_spec_from_request
(
api_request
:
dict
[
str
,
Any
])
->
dict
[
str
,
Any
]
:
graph_data_range
,
graph_recipes
=
graph_recipes_for_api_request
(
api_request
)
try
:
...
...
cmk/gui/plugins/metrics/graph_pdf.py
View file @
03f8ac51
...
...
@@ -7,21 +7,32 @@
from
typing
import
List
,
Optional
from
cmk.utils.type_defs
import
Timestamp