promtext-cli 0.1.2.dev97__py3-none-any.whl → 0.1.2.dev100__py3-none-any.whl

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.
promtext_cli/main.py CHANGED
@@ -1,152 +1,12 @@
1
- """promtext_cli is providing a CLI to cleanly update prometheus textfiles from scripts"""
1
+ """Provide the Entrypoints"""
2
2
 
3
- # pylint: disable=C0116,R0914,R0912,R0915
4
- # this rules will be fixed by a object-oriented refactoring
3
+ from .promtext import Promtext
5
4
 
6
- import argparse
7
- from pathlib import Path
8
- import logging
9
- import sys
10
5
 
11
- from prometheus_client.parser import text_string_to_metric_families
12
- from prometheus_client import CollectorRegistry, Gauge, write_to_textfile
13
-
14
-
15
- def promtext():
16
- # setup argpars
17
- # required file first
18
- parser = argparse.ArgumentParser(description="Prometheus textfile helper")
19
- parser.add_argument(
20
- "filename",
21
- type=str,
22
- help="Path to existing or new prometheus textfile, will be updated",
23
- )
24
-
25
- # metric name, required
26
- parser.add_argument("metric", type=str, help="metric name (new or updated)")
27
-
28
- # metric value as int/float, required
29
- parser.add_argument("value", type=float, help="metric value")
30
-
31
- # metric documentation as optional argument
32
- parser.add_argument(
33
- "--docs",
34
- type=str,
35
- help="metric documentation",
36
- default="metric appended by promtext-cli",
37
- )
38
-
39
- # labels, key-value, minimum 0, repeatable
40
- parser.add_argument(
41
- "--label", metavar="KEY=VALUE", help="label key=value pairs", action="append"
42
- )
43
-
44
- # log level from argparse
45
- parser.add_argument(
46
- "-v",
47
- "--verbose",
48
- action="store_const",
49
- dest="loglevel",
50
- const=logging.INFO,
51
- )
52
- args = parser.parse_args()
53
- logging.basicConfig(level=args.loglevel)
54
- logger = logging.getLogger(__name__)
55
-
56
- # processing: check if file is available, if yes, parse
57
- textfile = Path(args.filename)
58
-
59
- registry = CollectorRegistry()
60
- metrics = {}
61
-
62
- # check if args.filename exists with pathlib
63
- if textfile.is_file():
64
- for f in text_string_to_metric_families(textfile.read_text(encoding="utf-8")):
65
- # per metric: iterate over samples, create metric in registry
66
- m = False
67
- samples = []
68
- for s in f.samples:
69
- samples.append(s)
70
- if len(samples) > 0:
71
- # if we have samples, use the labelnames from them
72
- labelnames = list(samples[0].labels.keys())
73
- # metric-type specific init
74
- if f.type == "gauge":
75
- m = Gauge(
76
- f.name,
77
- f.documentation,
78
- unit=f.unit,
79
- labelnames=labelnames,
80
- registry=registry,
81
- )
82
- else:
83
- # we don't support other types yet, continue in these cases
84
- logger.warning("unsupported metric type %s, dropping", f.type)
85
- continue
86
- for s in samples:
87
- if len(labelnames) > 0:
88
- labelvalues = list(s.labels.values())
89
- m.labels(*labelvalues).set(s.value)
90
- else:
91
- m.set(s.value)
92
- metrics[f.name] = m
93
- logger.info(
94
- "copy gauge metric %s with labels %s from old file",
95
- f.name,
96
- ", ".join(labelnames),
97
- )
98
- else:
99
- logger.warning("got empty metric %s from old file, dropping", f.name)
100
-
101
- # add new metric from commandline
102
- m = False
103
-
104
- # figure out labelkey- and values
105
- labels = {}
106
- if args.label:
107
- for lpair in args.label:
108
- k, v = lpair.split("=")
109
- labels[k] = v
110
-
111
- labelvalues = []
112
- # here, we use a new metric
113
- if args.metric not in metrics:
114
- logger.info("adding new metric %s", args.metric)
115
- m = Gauge(args.metric, args.docs, registry=registry, labelnames=labels.keys())
116
- labelvalues = labels.values()
117
- else:
118
- m = metrics[args.metric]
119
-
120
- # There is no way to access existing labelnames directly
121
- # pylint: disable=W0212
122
- old_labelnames = list(m._labelnames)
123
- for la in old_labelnames:
124
- logger.info("processing label %s", la)
125
- if la in labels: # labelvalues are needed in order!
126
- labelvalues.append(labels[la])
127
- else:
128
- logger.error("previously known label '%s' missing, cannot update!", la)
129
- sys.exit(1)
130
- if len(old_labelnames) != len(labels.keys()):
131
- logger.error(
132
- "labelnames for metric %s not the same, cannot update! Old: %s, New: %s",
133
- args.metric,
134
- old_labelnames,
135
- list(labels.keys()),
136
- )
137
- sys.exit(1)
138
- logger.info("updating metric %s", args.metric)
139
-
140
- # actually set the value
141
- if len(labelvalues) > 0:
142
- m.labels(*labelvalues).set(args.value)
143
- else:
144
- m.set(args.value)
145
-
146
- # write to file
147
- write_to_textfile(args.filename, registry)
148
- logger.info("wrote to %s", args.filename)
6
+ def main():
7
+ """Main method invoking the core class"""
8
+ Promtext().cli_entrypoint()
149
9
 
150
10
 
151
11
  if __name__ == "__main__":
152
- promtext()
12
+ main()
@@ -0,0 +1,184 @@
1
+ """module providing the core functionality"""
2
+
3
+ import argparse
4
+ import logging
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ from prometheus_client import CollectorRegistry, Gauge, write_to_textfile
9
+ from prometheus_client.parser import text_string_to_metric_families
10
+
11
+
12
+ class Promtext:
13
+ """Class for the core functionality"""
14
+
15
+ def __init__(self):
16
+ self.textfile = None
17
+ self.logger = None
18
+ self.args = None
19
+ self.registry = CollectorRegistry()
20
+
21
+ self.metrics = {}
22
+
23
+ def _arguments(self):
24
+ """Load every input item from arguments & define cli"""
25
+ # required file first
26
+ parser = argparse.ArgumentParser(description="Prometheus textfile helper")
27
+ parser.add_argument(
28
+ "filename",
29
+ type=str,
30
+ help="Path to existing or new prometheus textfile, will be updated",
31
+ )
32
+
33
+ # metric name, required
34
+ parser.add_argument("metric", type=str, help="metric name (new or updated)")
35
+
36
+ # metric value as int/float, required
37
+ parser.add_argument("value", type=float, help="metric value")
38
+
39
+ # metric documentation as optional argument
40
+ parser.add_argument(
41
+ "--docs",
42
+ type=str,
43
+ help="metric documentation",
44
+ default="metric appended by promtext-cli",
45
+ )
46
+
47
+ # labels, key-value, minimum 0, repeatable
48
+ parser.add_argument(
49
+ "--label",
50
+ metavar="KEY=VALUE",
51
+ help="label key=value pairs",
52
+ action="append",
53
+ )
54
+
55
+ # log level from argparse
56
+ parser.add_argument(
57
+ "-v",
58
+ "--verbose",
59
+ action="store_const",
60
+ dest="loglevel",
61
+ const=logging.INFO,
62
+ )
63
+ self.args = parser.parse_args()
64
+
65
+ # processing: check if file is available, if yes, parse
66
+ self.textfile = Path(self.args.filename)
67
+
68
+ def parse_file(self):
69
+ """If possible, convert the input textfile to metrics in the registry"""
70
+ # check if self.args.filename exists with pathlib
71
+ if self.textfile.is_file():
72
+ for f in text_string_to_metric_families(
73
+ self.textfile.read_text(encoding="utf-8"),
74
+ ):
75
+ # per metric: iterate over samples, create metric in registry
76
+ m = False
77
+ samples = list(f.samples)
78
+ if len(samples) > 0:
79
+ # if we have samples, use the labelnames from them
80
+ labelnames = list(samples[0].labels.keys())
81
+ # metric-type specific init
82
+ if f.type == "gauge":
83
+ m = Gauge(
84
+ f.name,
85
+ f.documentation,
86
+ unit=f.unit,
87
+ labelnames=labelnames,
88
+ registry=self.registry,
89
+ )
90
+ else:
91
+ # we don't support other types yet, continue in these cases
92
+ self.logger.warning(
93
+ "unsupported metric type %s, dropping",
94
+ f.type,
95
+ )
96
+ continue
97
+ for s in samples:
98
+ if len(labelnames) > 0:
99
+ labelvalues = list(s.labels.values())
100
+ m.labels(*labelvalues).set(s.value)
101
+ else:
102
+ m.set(s.value)
103
+ self.metrics[f.name] = m
104
+ self.logger.info(
105
+ "copy gauge metric %s with labels %s from old file",
106
+ f.name,
107
+ ", ".join(labelnames),
108
+ )
109
+ else:
110
+ self.logger.warning(
111
+ "got empty metric %s from old file, dropping",
112
+ f.name,
113
+ )
114
+
115
+ def _build_metrics(self):
116
+ # add new metric from commandline
117
+ m = False
118
+
119
+ # figure out labelkey- and values
120
+ labels = {}
121
+ if self.args.label:
122
+ for lpair in self.args.label:
123
+ k, v = lpair.split("=")
124
+ labels[k] = v
125
+
126
+ labelvalues = []
127
+ # here, we use a new metric
128
+ if self.args.metric not in self.metrics:
129
+ self.logger.info("adding new metric %s", self.args.metric)
130
+ m = Gauge(
131
+ self.args.metric,
132
+ self.args.docs,
133
+ registry=self.registry,
134
+ labelnames=labels.keys(),
135
+ )
136
+ labelvalues = labels.values()
137
+ else:
138
+ m = self.metrics[self.args.metric]
139
+
140
+ # There is no way to access existing labelnames directly
141
+ # pylint: disable=W0212
142
+ old_labelnames = list(m._labelnames) # noqa: SLF001
143
+ for la in old_labelnames:
144
+ self.logger.info("processing label %s", la)
145
+ if la in labels: # labelvalues are needed in order!
146
+ labelvalues.append(labels[la])
147
+ else:
148
+ self.logger.error(
149
+ "previously known label '%s' missing, cannot update!",
150
+ la,
151
+ )
152
+ sys.exit(1)
153
+ if len(old_labelnames) != len(labels.keys()):
154
+ self.logger.error(
155
+ """labelnames for metric %s not the same, cannot update!
156
+ Old: %s, New: %s""",
157
+ self.args.metric,
158
+ old_labelnames,
159
+ list(labels.keys()),
160
+ )
161
+ sys.exit(1)
162
+ self.logger.info("updating metric %s", self.args.metric)
163
+
164
+ # actually set the value
165
+ if len(labelvalues) > 0:
166
+ m.labels(*labelvalues).set(self.args.value)
167
+ else:
168
+ m.set(self.args.value)
169
+
170
+ def output_file(self):
171
+ """Output to a textfile"""
172
+ write_to_textfile(self.textfile, self.registry)
173
+ self.logger.info("wrote to %s", self.textfile)
174
+
175
+ def cli_entrypoint(self):
176
+ """Main method called from the CLI"""
177
+ self._arguments()
178
+
179
+ logging.basicConfig(level=self.args.loglevel)
180
+ self.logger = logging.getLogger(__name__)
181
+
182
+ self.parse_file()
183
+ self._build_metrics()
184
+ self.output_file()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: promtext-cli
3
- Version: 0.1.2.dev97
3
+ Version: 0.1.2.dev100
4
4
  Summary: Prometheus Textfile Tooling
5
5
  Project-URL: Documentation, https://codeberg.org/margau/promtext-cli/src/branch/main#readme
6
6
  Project-URL: Issues, https://codeberg.org/margau/promtext-cli/issues
@@ -0,0 +1,7 @@
1
+ promtext_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ promtext_cli/main.py,sha256=4laMsJ9J1w1peJxv_QfvdRir6zXn19AmGFaEuo1dcRs,194
3
+ promtext_cli/promtext.py,sha256=yJMTHvMi6g-frMOgn1sXy0rcBQnxuVTsIr_AV2mVo1A,6449
4
+ promtext_cli-0.1.2.dev100.dist-info/METADATA,sha256=8w4dbLRmXcFYaR552lX_nOx86Q8lOIbMg_uhdpbu1wk,3415
5
+ promtext_cli-0.1.2.dev100.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
6
+ promtext_cli-0.1.2.dev100.dist-info/entry_points.txt,sha256=qH5Z6dM8QLK7tQ0RrdWZQtRcsdCyaGSU1WXygIcaRRc,52
7
+ promtext_cli-0.1.2.dev100.dist-info/RECORD,,
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ promtext = promtext_cli:main.main
@@ -1,6 +0,0 @@
1
- promtext_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- promtext_cli/main.py,sha256=Ce6GRsfi1IkHyatbENEZ8kTsoWnaoow_gRlwZRKMNYg,5054
3
- promtext_cli-0.1.2.dev97.dist-info/METADATA,sha256=hHwnIyJnYDRdO453zR88dA7KdqwKUYaypRzPQfWIZ-I,3414
4
- promtext_cli-0.1.2.dev97.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
5
- promtext_cli-0.1.2.dev97.dist-info/entry_points.txt,sha256=mIY1sCmFCjCpCfn3px-BajeXOaKZIA7iR5_fCaUJ4gg,56
6
- promtext_cli-0.1.2.dev97.dist-info/RECORD,,
@@ -1,2 +0,0 @@
1
- [console_scripts]
2
- promtext = promtext_cli.main:promtext