robotframework-prometheus 0.6.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,78 @@
1
+ Metadata-Version: 2.1
2
+ Name: robotframework-prometheus
3
+ Version: 0.6.1
4
+ Summary: Additional Robot Framework keywords
5
+ Home-page: https://github.com/test-fullautomation/robotframework-prometheus
6
+ Author: Holger Queckenstedt
7
+ Author-email: Holger.Queckenstedt@de.bosch.com
8
+ License: UNKNOWN
9
+ Platform: UNKNOWN
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: Apache Software License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Topic :: Software Development
16
+ Requires-Python: >=3.0
17
+ Description-Content-Type: text/markdown
18
+
19
+ Package Description
20
+ ===================
21
+
22
+ The interface library **prometheus\_interface** provides Robot Framework
23
+ keywords to communicate with the monitoring system **Prometheus**.
24
+
25
+ Currently this library is under development. We work on it. But what is
26
+ available up to now, is not ready for being used in productive systems
27
+ (but hopefully will be in near future).
28
+
29
+ Package Documentation
30
+ ---------------------
31
+
32
+ A (growing) detailed documentation of the **prometheus\_interface** can
33
+ be found here:
34
+
35
+ [PrometheusInterface.pdf](https://github.com/test-fullautomation/robotframework-prometheus/blob/develop/PrometheusInterface/PrometheusInterface.pdf)
36
+
37
+ Feedback
38
+ --------
39
+
40
+ To give us a feedback, you can send an email to [Thomas
41
+ Pollerspöck](mailto:Thomas.Pollerspoeck@de.bosch.com)
42
+
43
+ In case you want to report a bug or request any interesting feature,
44
+ please don\'t hesitate to raise a ticket.
45
+
46
+ Maintainers
47
+ -----------
48
+
49
+ [Holger Queckenstedt](mailto:Holger.Queckenstedt@de.bosch.com)
50
+
51
+ [Thomas Pollerspöck](mailto:Thomas.Pollerspoeck@de.bosch.com)
52
+
53
+ Contributors
54
+ ------------
55
+
56
+ [Holger Queckenstedt](mailto:Holger.Queckenstedt@de.bosch.com)
57
+
58
+ [Thomas Pollerspöck](mailto:Thomas.Pollerspoeck@de.bosch.com)
59
+
60
+ License
61
+ -------
62
+
63
+ Copyright 2020-2024 Robert Bosch GmbH
64
+
65
+ Licensed under the Apache License, Version 2.0 (the \"License\"); you
66
+ may not use this file except in compliance with the License. You may
67
+ obtain a copy of the License at
68
+
69
+ > [![License: Apache
70
+ > v2](https://img.shields.io/pypi/l/robotframework.svg)](http://www.apache.org/licenses/LICENSE-2.0.html)
71
+
72
+ Unless required by applicable law or agreed to in writing, software
73
+ distributed under the License is distributed on an \"AS IS\" BASIS,
74
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
75
+ See the License for the specific language governing permissions and
76
+ limitations under the License.
77
+
78
+
@@ -0,0 +1,13 @@
1
+ # Copyright 2020-2024 Robert Bosch GmbH
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
@@ -0,0 +1,697 @@
1
+ # Copyright 2020-2024 Robert Bosch GmbH
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # XC-HWP/ESW3-Queckenstedt
16
+
17
+ # -- import standard Python modules
18
+ import pickle, os, time, random
19
+ import dotdict
20
+
21
+ # -- import Prometheus interface
22
+ from prometheus_client import start_http_server, Gauge, Counter, Info
23
+
24
+ # -- import Robotframework API
25
+ from robot.api.deco import keyword, library # required when using @keyword, @library decorators
26
+ from robot.libraries.BuiltIn import BuiltIn
27
+
28
+ # -- import some helpers
29
+ from PythonExtensionsCollection.String.CString import CString
30
+ from PythonExtensionsCollection.Utils.CUtils import *
31
+
32
+ # --------------------------------------------------------------------------------------------------------------
33
+ # this interface library
34
+ #
35
+ LIBRARY_VERSION = "0.6.1"
36
+ LIBRARY_VERSION_DATE = "17.06.2024"
37
+ #
38
+ THISMODULENAME = "prometheus_interface.py"
39
+ THISMODULE = f"{THISMODULENAME} v. {LIBRARY_VERSION} / {LIBRARY_VERSION_DATE}"
40
+ #
41
+ DEFAULT_PORT = 8000
42
+ #
43
+ DEFAULT_MESSAGE_LEVEL = "INFO"
44
+ #
45
+ # --------------------------------------------------------------------------------------------------------------
46
+ #
47
+ @library
48
+ class prometheus_interface():
49
+ """The class 'prometheus_interface' provides to communicate with the monitoring system Prometheus.
50
+ For this purpose the 'Prometheus Python client library' is used.
51
+ """
52
+
53
+ ROBOT_AUTO_KEYWORDS = False # only decorated methods are keywords
54
+ ROBOT_LIBRARY_VERSION = LIBRARY_VERSION
55
+ ROBOT_LIBRARY_SCOPE = 'GLOBAL'
56
+
57
+ # --------------------------------------------------------------------------------------------------------------
58
+ #TM***
59
+
60
+ def __init__(self, port_number=DEFAULT_PORT, message_level=DEFAULT_MESSAGE_LEVEL):
61
+ self.__sMessageLevel = message_level
62
+ self.__port_number = port_number
63
+
64
+ # prometheus metric types
65
+ self.__dictCounter = {}
66
+ self.__dictGauges = {}
67
+ self.__dictInfos = {}
68
+
69
+ start_http_server(self.__port_number)
70
+
71
+ # default info metric about this interface library
72
+ oInfo = Info("Prometheus_interface", "Prometheus interface info")
73
+ dictInfo = {}
74
+ dictInfo['file name'] = THISMODULENAME
75
+ dictInfo['version'] = LIBRARY_VERSION
76
+ dictInfo['date'] = LIBRARY_VERSION_DATE
77
+ dictInfo['location'] = self.where_am_i()
78
+ oInfo.info(dictInfo)
79
+
80
+
81
+ def __del__(self):
82
+ del self.__dictCounter
83
+ del self.__dictGauges
84
+ del self.__dictInfos
85
+
86
+ # --------------------------------------------------------------------------------------------------------------
87
+ # -- library informations
88
+ # --------------------------------------------------------------------------------------------------------------
89
+ #TM***
90
+
91
+ @keyword
92
+ def get_version(self):
93
+ """Returns the version of this interface library
94
+ """
95
+ return LIBRARY_VERSION
96
+
97
+ @keyword
98
+ def who_am_i(self):
99
+ """Returns the full name of this interface library
100
+ """
101
+ return THISMODULE
102
+
103
+ @keyword
104
+ def where_am_i(self):
105
+ """Returns path to this interface library
106
+ """
107
+ location = CString.NormalizePath(os.path.dirname(os.path.abspath(__file__)))
108
+ return location
109
+
110
+ @keyword
111
+ def get_port_number(self):
112
+ """Returns the port number assigned to this instance of the library
113
+ """
114
+ return self.__port_number
115
+
116
+
117
+ # --------------------------------------------------------------------------------------------------------------
118
+ # -- prometheus metric type 'Info'
119
+ # --------------------------------------------------------------------------------------------------------------
120
+ #TM***
121
+
122
+ @keyword
123
+ def add_info(self, name=None, description=None, labels=None):
124
+ """add_info
125
+ """
126
+ success = False
127
+ result = "UNKNOWN"
128
+ if name is None:
129
+ result = "Parameter 'name' not defined"
130
+ return success, result
131
+ if description is None:
132
+ result = "Parameter 'description' not defined"
133
+ return success, result
134
+ if name in self.__dictInfos:
135
+ result = f"An info with name '{name}' is already defined"
136
+ return success, result
137
+ oInfo = None
138
+ if labels is None:
139
+ oInfo = Info(name, description)
140
+ else:
141
+ labellist = labels.split(';')
142
+ listLabelNames = []
143
+ for label in labellist:
144
+ label = label.strip()
145
+ listLabelNames.append(label)
146
+ oInfo = Info(name, description, listLabelNames)
147
+ self.__dictInfos[name] = oInfo
148
+ success = True
149
+ listResults = []
150
+ listResults.append(f"Info '{name}' added")
151
+ if labels is not None:
152
+ listResults.append(f"with labels: '{labels}'")
153
+ result = " ".join(listResults)
154
+ return success, result
155
+
156
+ @keyword
157
+ def set_info(self, name=None, info=None, labels=None):
158
+ """set_info
159
+ """
160
+ success = False
161
+ result = "UNKNOWN"
162
+ if name is None:
163
+ result = "Parameter 'name' not defined"
164
+ return success, result
165
+ if info is None:
166
+ result = "Parameter 'info' not defined"
167
+ return success, result
168
+ if name not in self.__dictInfos:
169
+ result = f"Info '{name}' not defined"
170
+ return success, result
171
+ dictInfo = {}
172
+ list_splitparts = info.split(';')
173
+ for splitpart in list_splitparts:
174
+ splitpart = splitpart.strip()
175
+ list_splitparts2 = splitpart.split(':')
176
+ if len(list_splitparts2) != 2:
177
+ success = False
178
+ result = "Syntax error in parameter 'info' of '{name}': missing delimiter"
179
+ return success, result
180
+ param_name = list_splitparts2[0].strip()
181
+ if param_name == "":
182
+ success = False
183
+ result = "Syntax error in parameter 'info' of '{name}': parameter name is empty"
184
+ return success, result
185
+ param_value = list_splitparts2[1].strip()
186
+ if param_value == "":
187
+ success = False
188
+ result = "Syntax error in parameter 'info' of '{name}': parameter value is empty"
189
+ return success, result
190
+ dictInfo[param_name] = str(param_value)
191
+ oInfo = self.__dictInfos[name]
192
+ if labels is None:
193
+ oInfo.info(dictInfo)
194
+ else:
195
+ labellist = labels.split(';')
196
+ listLabelValues = []
197
+ for label in labellist:
198
+ label = label.strip()
199
+ listLabelValues.append(label)
200
+ oInfo.labels(*listLabelValues).info(dictInfo)
201
+ success = True
202
+ listResults = []
203
+ listResults.append(f"Info '{name}' set to'{info}'")
204
+ if labels is not None:
205
+ listResults.append(f"with labels: '{labels}'")
206
+ result = " ".join(listResults)
207
+ return success, result
208
+
209
+
210
+ # TODO lighting reaktivieren (as example)
211
+
212
+ # # @keyword
213
+ # # def add_lighting(self):
214
+ # # """add_lighting (experimental only)
215
+ # # """
216
+ # # self.__oLighting = Info('lighting', ': kind of lighting')
217
+
218
+ # # @keyword
219
+ # # def set_daylight(self):
220
+ # # """set_daylight (experimental only)
221
+ # # """
222
+ # # self.__oLighting.info({'lighting' : 'daylight'})
223
+
224
+ # # @keyword
225
+ # # def set_nightlight(self):
226
+ # # """set_nightlight (experimental only)
227
+ # # """
228
+ # # self.__oLighting.info({'lighting' : 'nightlight'})
229
+
230
+
231
+ # --------------------------------------------------------------------------------------------------------------
232
+ # -- prometheus metric type 'Counter'
233
+ # --------------------------------------------------------------------------------------------------------------
234
+ #TM***
235
+
236
+ @keyword
237
+ def add_counter(self, name=None, description=None, labels=None):
238
+ """This keyword adds a new counter. The values of existing counters can be changed with ``inc_counter``.
239
+
240
+ **Arguments:**
241
+
242
+ * ``name``
243
+
244
+ The name of the new counter
245
+
246
+ / *Condition*: required / *Type*: str /
247
+
248
+ * ``description``
249
+
250
+ The description of the new counter
251
+
252
+ / *Condition*: required / *Type*: str /
253
+
254
+ * ``labels``
255
+
256
+ A semicolon separated list of label names assigned to the new counter
257
+
258
+ / *Condition*: optional / *Type*: str / *Default*: None /
259
+
260
+ **Returns:**
261
+
262
+ * ``success``
263
+
264
+ / *Type*: bool /
265
+
266
+ Indicates if the computation of the keyword was successful or not
267
+
268
+ * ``result``
269
+
270
+ / *Type*: str /
271
+
272
+ The result of the computation of the keyword
273
+ """
274
+ success = False
275
+ result = "UNKNOWN"
276
+ if name is None:
277
+ result = "Parameter 'name' not defined"
278
+ return success, result
279
+ if description is None:
280
+ result = "Parameter 'description' not defined"
281
+ return success, result
282
+ if name in self.__dictCounter:
283
+ result = f"A counter with name '{name}' is already defined"
284
+ return success, result
285
+ oCounter = None
286
+ if labels is None:
287
+ oCounter = Counter(name, description)
288
+ else:
289
+ labellist = labels.split(';')
290
+ listLabelNames = []
291
+ for label in labellist:
292
+ label = label.strip()
293
+ listLabelNames.append(label)
294
+ oCounter = Counter(name, description, listLabelNames)
295
+ self.__dictCounter[name] = oCounter
296
+ success = True
297
+ listResults = []
298
+ listResults.append(f"Counter '{name}' added")
299
+ if labels is not None:
300
+ listResults.append(f"with labels: '{labels}'")
301
+ result = " ".join(listResults)
302
+ return success, result
303
+ # eof def add_counter(...):
304
+
305
+ @keyword
306
+ def inc_counter(self, name=None, value=None, labels=None):
307
+ """This keyword increments a counter. The counter has to be added with '``add_counter``' before.
308
+
309
+ **Arguments:**
310
+
311
+ * ``name``
312
+
313
+ The name of the counter
314
+
315
+ / *Condition*: required / *Type*: str /
316
+
317
+ * ``value``
318
+
319
+ The value of increment. If not given, the value of the counter is incremented by value 1.
320
+
321
+ / *Condition*: optional / *Type*: int / *Default*: None /
322
+
323
+ * ``labels``
324
+
325
+ A semicolon separated list of labels assigned to the counter. The order of labels must fit to the order of label names like defined in ``add_counter``.
326
+
327
+ / *Condition*: optional / *Type*: str / *Default*: None /
328
+
329
+ **Returns:**
330
+
331
+ * ``success``
332
+
333
+ / *Type*: bool /
334
+
335
+ Indicates if the computation of the keyword was successful or not
336
+
337
+ * ``result``
338
+
339
+ / *Type*: str /
340
+
341
+ The result of the computation of the keyword
342
+ """
343
+ success = False
344
+ result = "UNKNOWN"
345
+ if name is None:
346
+ result = "Parameter 'name' not defined"
347
+ return success, result
348
+ if name not in self.__dictCounter:
349
+ result = f"Counter '{name}' not defined"
350
+ return success, result
351
+ if value is not None:
352
+ try:
353
+ value = int(value)
354
+ except Exception as ex:
355
+ success = False
356
+ result = str(ex)
357
+ return success, result
358
+ oCounter = self.__dictCounter[name]
359
+ if labels is None:
360
+ if value is None:
361
+ oCounter.inc()
362
+ else:
363
+ oCounter.inc(value)
364
+ else:
365
+ labellist = labels.split(';')
366
+ listLabelValues = []
367
+ for label in labellist:
368
+ label = label.strip()
369
+ listLabelValues.append(label)
370
+ if value is None:
371
+ oCounter.labels(*listLabelValues).inc()
372
+ else:
373
+ oCounter.labels(*listLabelValues).inc(value)
374
+ success = True
375
+ listResults = []
376
+ listResults.append(f"Counter '{name}' incremented")
377
+ if value is not None:
378
+ listResults.append(f"by value '{value}'")
379
+ if labels is not None:
380
+ listResults.append(f"with labels: '{labels}'")
381
+ result = " ".join(listResults)
382
+ return success, result
383
+ # eof def inc_counter(...):
384
+
385
+
386
+ # --------------------------------------------------------------------------------------------------------------
387
+ # -- prometheus metric type 'Gauge'
388
+ # --------------------------------------------------------------------------------------------------------------
389
+ #TM***
390
+
391
+ @keyword
392
+ def add_gauge(self, name=None, description=None, labels=None):
393
+ """This keyword adds a new gauge. The values of existing gauges can be changed with ``set_gauge``, ``inc_gauge`` and ``dec_gauge``.
394
+
395
+ **Arguments:**
396
+
397
+ * ``name``
398
+
399
+ The name of the new gauge
400
+
401
+ / *Condition*: required / *Type*: str /
402
+
403
+ * ``description``
404
+
405
+ The description of the new gauge
406
+
407
+ / *Condition*: required / *Type*: str /
408
+
409
+ * ``labels``
410
+
411
+ A semicolon separated list of label names assigned to the new gauge
412
+
413
+ / *Condition*: optional / *Type*: str / *Default*: None /
414
+
415
+ **Returns:**
416
+
417
+ * ``success``
418
+
419
+ / *Type*: bool /
420
+
421
+ Indicates if the computation of the keyword was successful or not
422
+
423
+ * ``result``
424
+
425
+ / *Type*: str /
426
+
427
+ The result of the computation of the keyword
428
+ """
429
+ success = False
430
+ result = "UNKNOWN"
431
+ if name is None:
432
+ result = "Parameter 'name' not defined"
433
+ return success, result
434
+ if description is None:
435
+ result = "Parameter 'description' not defined"
436
+ return success, result
437
+ if name in self.__dictGauges:
438
+ result = f"A gauge with name '{name}' is already defined"
439
+ return success, result
440
+ oGauge = None
441
+ if labels is None:
442
+ oGauge = Gauge(name, description)
443
+ else:
444
+ labellist = labels.split(';')
445
+ listLabelNames = []
446
+ for label in labellist:
447
+ label = label.strip()
448
+ listLabelNames.append(label)
449
+ oGauge = Gauge(name, description, listLabelNames)
450
+ self.__dictGauges[name] = oGauge
451
+ success = True
452
+ listResults = []
453
+ listResults.append(f"Gauge '{name}' added")
454
+ if labels is not None:
455
+ listResults.append(f"with labels: '{labels}'")
456
+ result = " ".join(listResults)
457
+ return success, result
458
+ # eof def add_gauge(...):
459
+
460
+ @keyword
461
+ def set_gauge(self, name=None, value=None, labels=None):
462
+ """This keyword sets the value for a gauge. The gauge has to be added with '``add_gauge``' before.
463
+
464
+ **Arguments:**
465
+
466
+ * ``name``
467
+
468
+ The name of the gauge
469
+
470
+ / *Condition*: required / *Type*: str /
471
+
472
+ * ``value``
473
+
474
+ The new value of the gauge.
475
+
476
+ / *Condition*: optional / *Type*: int / *Default*: None /
477
+
478
+ * ``labels``
479
+
480
+ A semicolon separated list of labels assigned to the gauge. The order of labels must fit to the order of label names like defined in ``add_gauge``.
481
+
482
+ / *Condition*: optional / *Type*: str / *Default*: None /
483
+
484
+ **Returns:**
485
+
486
+ * ``success``
487
+
488
+ / *Type*: bool /
489
+
490
+ Indicates if the computation of the keyword was successful or not
491
+
492
+ * ``result``
493
+
494
+ / *Type*: str /
495
+
496
+ The result of the computation of the keyword
497
+ """
498
+ success = False
499
+ result = "UNKNOWN"
500
+ if name is None:
501
+ result = "Parameter 'name' not defined"
502
+ return success, result
503
+ if name not in self.__dictGauges:
504
+ result = f"Gauge '{name}' not defined"
505
+ return success, result
506
+ if value is None:
507
+ result = "Parameter 'value' not defined"
508
+ return success, result
509
+ else:
510
+ try:
511
+ value = int(value)
512
+ except Exception as ex:
513
+ success = False
514
+ result = str(ex)
515
+ return success, result
516
+ oGauge = self.__dictGauges[name]
517
+ if labels is None:
518
+ oGauge.set(value)
519
+ else:
520
+ labellist = labels.split(';')
521
+ listLabelValues = []
522
+ for label in labellist:
523
+ label = label.strip()
524
+ listLabelValues.append(label)
525
+ oGauge.labels(*listLabelValues).set(value)
526
+ success = True
527
+ listResults = []
528
+ listResults.append(f"Gauge '{name}' set to value '{value}'")
529
+ if labels is not None:
530
+ listResults.append(f"with labels: '{labels}'")
531
+ result = " ".join(listResults)
532
+ return success, result
533
+ # eof def set_gauge(...):
534
+
535
+ @keyword
536
+ def inc_gauge(self, name=None, value=None, labels=None):
537
+ """This keyword increments a gauge. The gauge has to be added with '``add_gauge``' before.
538
+
539
+ **Arguments:**
540
+
541
+ * ``name``
542
+
543
+ The name of the gauge
544
+
545
+ / *Condition*: required / *Type*: str /
546
+
547
+ * ``value``
548
+
549
+ The value of increment. If not given, the value of the gauge is incremented by value 1.
550
+
551
+ / *Condition*: optional / *Type*: int / *Default*: None /
552
+
553
+ * ``labels``
554
+
555
+ A semicolon separated list of labels assigned to the gauge. The order of labels must fit to the order of label names like defined in ``add_gauge``.
556
+
557
+ / *Condition*: optional / *Type*: str / *Default*: None /
558
+
559
+ **Returns:**
560
+
561
+ * ``success``
562
+
563
+ / *Type*: bool /
564
+
565
+ Indicates if the computation of the keyword was successful or not
566
+
567
+ * ``result``
568
+
569
+ / *Type*: str /
570
+
571
+ The result of the computation of the keyword
572
+ """
573
+ success = False
574
+ result = "UNKNOWN"
575
+ if name is None:
576
+ result = "Parameter 'name' not defined"
577
+ return success, result
578
+ if name not in self.__dictGauges:
579
+ result = f"Gauge '{name}' not defined"
580
+ return success, result
581
+ if value is not None:
582
+ try:
583
+ value = int(value)
584
+ except Exception as ex:
585
+ success = False
586
+ result = str(ex)
587
+ return success, result
588
+ oGauge = self.__dictGauges[name]
589
+ if labels is None:
590
+ if value is None:
591
+ oGauge.inc()
592
+ else:
593
+ oGauge.inc(value)
594
+ else:
595
+ labellist = labels.split(';')
596
+ listLabelValues = []
597
+ for label in labellist:
598
+ label = label.strip()
599
+ listLabelValues.append(label)
600
+ if value is None:
601
+ oGauge.labels(*listLabelValues).inc()
602
+ else:
603
+ oGauge.labels(*listLabelValues).inc(value)
604
+ success = True
605
+ listResults = []
606
+ listResults.append(f"Gauge '{name}' incremented")
607
+ if value is not None:
608
+ listResults.append(f"by value '{value}'")
609
+ if labels is not None:
610
+ listResults.append(f"with labels: '{labels}'")
611
+ result = " ".join(listResults)
612
+ return success, result
613
+ # eof def inc_gauge(...):
614
+
615
+ @keyword
616
+ def dec_gauge(self, name=None, value=None, labels=None):
617
+ """This keyword decrements a gauge. The gauge has to be added with '``add_gauge``' before.
618
+
619
+ **Arguments:**
620
+
621
+ * ``name``
622
+
623
+ The name of the gauge
624
+
625
+ / *Condition*: required / *Type*: str /
626
+
627
+ * ``value``
628
+
629
+ The value of decrement. If not given, the value of the gauge is decremented by value 1.
630
+
631
+ / *Condition*: optional / *Type*: int / *Default*: None /
632
+
633
+ * ``labels``
634
+
635
+ A semicolon separated list of labels assigned to the gauge. The order of labels must fit to the order of label names like defined in ``add_gauge``.
636
+
637
+ / *Condition*: optional / *Type*: str / *Default*: None /
638
+
639
+ **Returns:**
640
+
641
+ * ``success``
642
+
643
+ / *Type*: bool /
644
+
645
+ Indicates if the computation of the keyword was successful or not
646
+
647
+ * ``result``
648
+
649
+ / *Type*: str /
650
+
651
+ The result of the computation of the keyword
652
+ """
653
+ success = False
654
+ result = "UNKNOWN"
655
+ if name is None:
656
+ result = "Parameter 'name' not defined"
657
+ return success, result
658
+ if name not in self.__dictGauges:
659
+ result = f"Gauge '{name}' not defined"
660
+ return success, result
661
+ if value is not None:
662
+ try:
663
+ value = int(value)
664
+ except Exception as ex:
665
+ success = False
666
+ result = str(ex)
667
+ return success, result
668
+ oGauge = self.__dictGauges[name]
669
+ if labels is None:
670
+ if value is None:
671
+ oGauge.dec()
672
+ else:
673
+ oGauge.dec(value)
674
+ else:
675
+ labellist = labels.split(';')
676
+ listLabelValues = []
677
+ for label in labellist:
678
+ label = label.strip()
679
+ listLabelValues.append(label)
680
+ if value is None:
681
+ oGauge.labels(*listLabelValues).dec()
682
+ else:
683
+ oGauge.labels(*listLabelValues).dec(value)
684
+ success = True
685
+ listResults = []
686
+ listResults.append(f"Gauge '{name}' decremented")
687
+ if value is not None:
688
+ listResults.append(f"by value '{value}'")
689
+ if labels is not None:
690
+ listResults.append(f"with labels: '{labels}'")
691
+ result = " ".join(listResults)
692
+ return success, result
693
+ # eof def dec_gauge(...):
694
+
695
+
696
+ # eof class prometheus_interface():
697
+
@@ -0,0 +1,73 @@
1
+ .. Copyright 2020-2024 Robert Bosch GmbH
2
+
3
+ .. Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ .. http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ .. Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
14
+
15
+ Package Description
16
+ ===================
17
+
18
+ The interface library **prometheus_interface** provides Robot Framework keywords to communicate with the monitoring system **Prometheus**.
19
+
20
+
21
+ Currently this library is under development. We work on it. But what is available up to now, is not ready for being used in productive systems
22
+ (but hopefully will be in near future).
23
+
24
+
25
+
26
+ Package Documentation
27
+ ---------------------
28
+
29
+ A (growing) detailed documentation of the **prometheus_interface** can be found here:
30
+
31
+ `PrometheusInterface.pdf <https://github.com/test-fullautomation/robotframework-prometheus/blob/develop/PrometheusInterface/PrometheusInterface.pdf>`_
32
+
33
+ Feedback
34
+ --------
35
+
36
+ To give us a feedback, you can send an email to `Thomas Pollerspöck <mailto:Thomas.Pollerspoeck@de.bosch.com>`_
37
+
38
+ In case you want to report a bug or request any interesting feature, please don't hesitate to raise a ticket.
39
+
40
+ Maintainers
41
+ -----------
42
+
43
+ `Holger Queckenstedt <mailto:Holger.Queckenstedt@de.bosch.com>`_
44
+
45
+ `Thomas Pollerspöck <mailto:Thomas.Pollerspoeck@de.bosch.com>`_
46
+
47
+ Contributors
48
+ ------------
49
+
50
+ `Holger Queckenstedt <mailto:Holger.Queckenstedt@de.bosch.com>`_
51
+
52
+ `Thomas Pollerspöck <mailto:Thomas.Pollerspoeck@de.bosch.com>`_
53
+
54
+ License
55
+ -------
56
+
57
+ Copyright 2020-2024 Robert Bosch GmbH
58
+
59
+ Licensed under the Apache License, Version 2.0 (the "License");
60
+ you may not use this file except in compliance with the License.
61
+ You may obtain a copy of the License at
62
+
63
+ |License: Apache v2|
64
+
65
+ Unless required by applicable law or agreed to in writing, software
66
+ distributed under the License is distributed on an "AS IS" BASIS,
67
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
68
+ See the License for the specific language governing permissions and
69
+ limitations under the License.
70
+
71
+
72
+ .. |License: Apache v2| image:: https://img.shields.io/pypi/l/robotframework.svg
73
+ :target: http://www.apache.org/licenses/LICENSE-2.0.html
@@ -0,0 +1,78 @@
1
+ Metadata-Version: 2.1
2
+ Name: robotframework-prometheus
3
+ Version: 0.6.1
4
+ Summary: Additional Robot Framework keywords
5
+ Home-page: https://github.com/test-fullautomation/robotframework-prometheus
6
+ Author: Holger Queckenstedt
7
+ Author-email: Holger.Queckenstedt@de.bosch.com
8
+ License: UNKNOWN
9
+ Platform: UNKNOWN
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: Apache Software License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Topic :: Software Development
16
+ Requires-Python: >=3.0
17
+ Description-Content-Type: text/markdown
18
+
19
+ Package Description
20
+ ===================
21
+
22
+ The interface library **prometheus\_interface** provides Robot Framework
23
+ keywords to communicate with the monitoring system **Prometheus**.
24
+
25
+ Currently this library is under development. We work on it. But what is
26
+ available up to now, is not ready for being used in productive systems
27
+ (but hopefully will be in near future).
28
+
29
+ Package Documentation
30
+ ---------------------
31
+
32
+ A (growing) detailed documentation of the **prometheus\_interface** can
33
+ be found here:
34
+
35
+ [PrometheusInterface.pdf](https://github.com/test-fullautomation/robotframework-prometheus/blob/develop/PrometheusInterface/PrometheusInterface.pdf)
36
+
37
+ Feedback
38
+ --------
39
+
40
+ To give us a feedback, you can send an email to [Thomas
41
+ Pollerspöck](mailto:Thomas.Pollerspoeck@de.bosch.com)
42
+
43
+ In case you want to report a bug or request any interesting feature,
44
+ please don\'t hesitate to raise a ticket.
45
+
46
+ Maintainers
47
+ -----------
48
+
49
+ [Holger Queckenstedt](mailto:Holger.Queckenstedt@de.bosch.com)
50
+
51
+ [Thomas Pollerspöck](mailto:Thomas.Pollerspoeck@de.bosch.com)
52
+
53
+ Contributors
54
+ ------------
55
+
56
+ [Holger Queckenstedt](mailto:Holger.Queckenstedt@de.bosch.com)
57
+
58
+ [Thomas Pollerspöck](mailto:Thomas.Pollerspoeck@de.bosch.com)
59
+
60
+ License
61
+ -------
62
+
63
+ Copyright 2020-2024 Robert Bosch GmbH
64
+
65
+ Licensed under the Apache License, Version 2.0 (the \"License\"); you
66
+ may not use this file except in compliance with the License. You may
67
+ obtain a copy of the License at
68
+
69
+ > [![License: Apache
70
+ > v2](https://img.shields.io/pypi/l/robotframework.svg)](http://www.apache.org/licenses/LICENSE-2.0.html)
71
+
72
+ Unless required by applicable law or agreed to in writing, software
73
+ distributed under the License is distributed on an \"AS IS\" BASIS,
74
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
75
+ See the License for the specific language governing permissions and
76
+ limitations under the License.
77
+
78
+
@@ -0,0 +1,10 @@
1
+ README.rst
2
+ setup.py
3
+ PrometheusInterface/PrometheusInterface.pdf
4
+ PrometheusInterface/__init__.py
5
+ PrometheusInterface/prometheus_interface.py
6
+ robotframework_prometheus.egg-info/PKG-INFO
7
+ robotframework_prometheus.egg-info/SOURCES.txt
8
+ robotframework_prometheus.egg-info/dependency_links.txt
9
+ robotframework_prometheus.egg-info/requires.txt
10
+ robotframework_prometheus.egg-info/top_level.txt
@@ -0,0 +1,3 @@
1
+ PythonExtensionsCollection
2
+ robotframework
3
+ prometheus-client
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,224 @@
1
+ # **************************************************************************************************************
2
+ #
3
+ # Copyright 2020-2024 Robert Bosch GmbH
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+ # **************************************************************************************************************
18
+ #
19
+ # setup.py
20
+ #
21
+ # XC-HWP/ESW3-Queckenstedt
22
+ #
23
+ # Extends the standard setuptools installation by adding the documentation in PDF format
24
+ # (requires installation mode) and tidying up some folders.
25
+ #
26
+ # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
27
+ #
28
+ # This script deletes folders (as defined in config.CRepositoryConfig, depending on the position of this script):
29
+ # - previous builds within this repository
30
+ # - previous installations within
31
+ # * <Python installation>\Lib\site-packages (Windows)
32
+ # * <Python installation>/../lib/python3.9/site-packages (Linux)
33
+ #
34
+ # before the build and the installation start again!
35
+ #
36
+ # !!! USE WITH CAUTION !!!
37
+ #
38
+ # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
39
+ #
40
+ # --------------------------------------------------------------------------------------------------------------
41
+ #
42
+ # * Hints:
43
+ #
44
+ # The usual
45
+ # packages = setuptools.find_packages(),
46
+ # is replaced by
47
+ # packages = [str(oRepositoryConfig.Get('PACKAGENAME')), ],
48
+ # to avoid that also config.CRepositoryConfig() and additions.CExtendedSetup() are part of the distribution.
49
+ # CRepositoryConfig and CExtendedSetup() are only repository internal helper.
50
+ #
51
+ # * Known issues:
52
+ #
53
+ # - setuptools do not properly update an existing package installation under <Python installation>\Lib\site-packages\<package name>!
54
+ # > Files modified manually within installation folder, are still modified after repeated execution of setuptools.
55
+ # > Files added manually within installation folder, are still present there after repeated execution of setuptools.
56
+ # > Only files deleted manually within installation folder, are are restored there after repeated execution of setuptools.
57
+ # - No such issues with <Python installation>\Lib\site-packages\<package name>-<versions>.egg-info.
58
+ # - Solution: explicit deletion of all previous output (all documentation-, build- and installation-folder, except the egg-info folder)
59
+ # (see 'delete_previous_build()' and 'delete_previous_installation()')
60
+ #
61
+ # --------------------------------------------------------------------------------------------------------------
62
+ #
63
+ # 24.06.2022
64
+ #
65
+ # --------------------------------------------------------------------------------------------------------------
66
+
67
+ import os, sys, platform, shlex, subprocess
68
+ import setuptools
69
+ from setuptools.command.install import install
70
+
71
+ # prefer the repository local version of all additional libraries (instead of the installed version under site-packages)
72
+ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "./additions")))
73
+
74
+ from config.CRepositoryConfig import CRepositoryConfig # providing repository and environment specific information
75
+ from additions.CExtendedSetup import CExtendedSetup # providing functions to support the extended setup process
76
+
77
+ import colorama as col
78
+
79
+ col.init(autoreset=True)
80
+
81
+ COLBR = col.Style.BRIGHT + col.Fore.RED
82
+ COLBY = col.Style.BRIGHT + col.Fore.YELLOW
83
+ COLBG = col.Style.BRIGHT + col.Fore.GREEN
84
+
85
+ SUCCESS = 0
86
+ ERROR = 1
87
+
88
+ # --------------------------------------------------------------------------------------------------------------
89
+
90
+ def printerror(sMsg):
91
+ sys.stderr.write(COLBR + f"Error: {sMsg}!\n")
92
+
93
+ def printexception(sMsg):
94
+ sys.stderr.write(COLBR + f"Exception: {sMsg}!\n")
95
+
96
+ # --------------------------------------------------------------------------------------------------------------
97
+
98
+ class ExtendedInstallCommand(install):
99
+ """Extended setup for installation mode."""
100
+
101
+ def run(self):
102
+
103
+ listCmdArgs = sys.argv
104
+ if ( ('install' in listCmdArgs) or ('build' in listCmdArgs) or ('sdist' in listCmdArgs) or ('bdist_wheel' in listCmdArgs) ):
105
+ install.run(self)
106
+ return SUCCESS
107
+
108
+ # eof class ExtendedInstallCommand(install):
109
+
110
+ # --------------------------------------------------------------------------------------------------------------
111
+
112
+ # -- Even in case of other command line parameters than 'install' or 'build' are used we need the following objects.
113
+ # (Without repository configuration commands like '--author-email' would not be possible)
114
+
115
+ # -- setting up the repository configuration
116
+ oRepositoryConfig = None
117
+ try:
118
+ oRepositoryConfig = CRepositoryConfig(os.path.abspath(sys.argv[0]))
119
+ except Exception as ex:
120
+ print()
121
+ printexception(str(ex))
122
+ print()
123
+ sys.exit(ERROR)
124
+
125
+ # -- setting up the extended setup
126
+ oExtendedSetup = None
127
+ try:
128
+ oExtendedSetup = CExtendedSetup(oRepositoryConfig)
129
+ except Exception as ex:
130
+ print()
131
+ printexception(str(ex))
132
+ print()
133
+ sys.exit(ERROR)
134
+
135
+ # --------------------------------------------------------------------------------------------------------------
136
+
137
+ long_description = "long description" # variable is required even in case of other command line parameters than 'install' or 'build' are used
138
+
139
+ listCmdArgs = sys.argv
140
+ if ( ('install' in listCmdArgs) or ('build' in listCmdArgs) or ('sdist' in listCmdArgs) or ('bdist_wheel' in listCmdArgs) ):
141
+ print()
142
+ print(COLBY + "Entering extended installation")
143
+ print()
144
+
145
+ print(COLBY + "Extended setup step 1/5: Calling the documentation builder")
146
+ print()
147
+
148
+ nReturn = oExtendedSetup.genpackagedoc()
149
+ if nReturn != SUCCESS:
150
+ sys.exit(nReturn)
151
+
152
+ print(COLBY + "Extended setup step 2/5: Converting the repository README")
153
+ print()
154
+
155
+ nReturn = oExtendedSetup.convert_repo_readme()
156
+ if nReturn != SUCCESS:
157
+ sys.exit(nReturn)
158
+
159
+ print(COLBY + "Extended setup step 3/5: Deleting previous setup outputs (build, dist, <package name>.egg-info within repository)")
160
+ print()
161
+
162
+ nReturn = oExtendedSetup.delete_previous_build()
163
+ if nReturn != SUCCESS:
164
+ sys.exit(nReturn)
165
+
166
+ if ( ('bdist_wheel' in listCmdArgs) or ('build' in listCmdArgs) ):
167
+ print()
168
+ print(COLBY + "Skipping extended setup step 4/5: Deleting previous package installation folder within site-packages")
169
+ print()
170
+ else:
171
+ print()
172
+ print(COLBY + "Extended setup step 4/5: Deleting previous package installation folder within site-packages") # (<package name> and <package name>_doc under <Python installation>\Lib\site-packages
173
+ print()
174
+ nReturn = oExtendedSetup.delete_previous_installation()
175
+ if nReturn != SUCCESS:
176
+ sys.exit(nReturn)
177
+
178
+ README_MD = str(oRepositoryConfig.Get('README_MD'))
179
+ with open(README_MD, "r", encoding="utf-8") as fh:
180
+ long_description = fh.read()
181
+ fh.close()
182
+
183
+ # --------------------------------------------------------------------------------------------------------------
184
+
185
+ # -- the 'setup' itself
186
+
187
+ print(COLBY + "Extended setup step 5/5: install.run(self)")
188
+ print()
189
+
190
+ setuptools.setup(
191
+ name = str(oRepositoryConfig.Get('REPOSITORYNAME')),
192
+ version = str(oRepositoryConfig.Get('PACKAGEVERSION')),
193
+ author = str(oRepositoryConfig.Get('AUTHOR')),
194
+ author_email = str(oRepositoryConfig.Get('AUTHOREMAIL')),
195
+ description = str(oRepositoryConfig.Get('DESCRIPTION')),
196
+ long_description = long_description,
197
+ long_description_content_type = str(oRepositoryConfig.Get('LONGDESCRIPTIONCONTENTTYPE')),
198
+ url = str(oRepositoryConfig.Get('URL')),
199
+ packages = [str(oRepositoryConfig.Get('PACKAGENAME')),],
200
+ package_dir = {str(oRepositoryConfig.Get('REPOSITORYNAME')) : str(oRepositoryConfig.Get('PACKAGENAME'))},
201
+ classifiers = [
202
+ str(oRepositoryConfig.Get('PROGRAMMINGLANGUAGE')),
203
+ str(oRepositoryConfig.Get('LICENCE')),
204
+ str(oRepositoryConfig.Get('OPERATINGSYSTEM')),
205
+ str(oRepositoryConfig.Get('DEVELOPMENTSTATUS')),
206
+ str(oRepositoryConfig.Get('INTENDEDAUDIENCE')),
207
+ str(oRepositoryConfig.Get('TOPIC')),
208
+ ],
209
+ python_requires = str(oRepositoryConfig.Get('PYTHONREQUIRES')),
210
+ cmdclass={
211
+ 'install': ExtendedInstallCommand,
212
+ },
213
+ install_requires = oRepositoryConfig.Get('INSTALLREQUIRES'),
214
+ package_data={f"{oRepositoryConfig.Get('PACKAGENAME')}" : oRepositoryConfig.Get('PACKAGEDATA')},
215
+ )
216
+
217
+ # --------------------------------------------------------------------------------------------------------------
218
+
219
+ print()
220
+ print(COLBG + "Extended installation done")
221
+ print()
222
+
223
+ # --------------------------------------------------------------------------------------------------------------
224
+