promtext-cli 0.1.2.dev96__py3-none-any.whl → 0.1.2.dev98__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 +6 -146
- promtext_cli/promtext.py +182 -0
- {promtext_cli-0.1.2.dev96.dist-info → promtext_cli-0.1.2.dev98.dist-info}/METADATA +1 -1
- promtext_cli-0.1.2.dev98.dist-info/RECORD +7 -0
- promtext_cli-0.1.2.dev98.dist-info/entry_points.txt +2 -0
- promtext_cli-0.1.2.dev96.dist-info/RECORD +0 -6
- promtext_cli-0.1.2.dev96.dist-info/entry_points.txt +0 -2
- {promtext_cli-0.1.2.dev96.dist-info → promtext_cli-0.1.2.dev98.dist-info}/WHEEL +0 -0
promtext_cli/main.py
CHANGED
|
@@ -1,152 +1,12 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""This module takes care of entrypoints"""
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
12
|
-
|
|
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
|
-
|
|
12
|
+
main()
|
promtext_cli/promtext.py
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""this is the module providing the core functionality"""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import logging
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
from prometheus_client.parser import text_string_to_metric_families
|
|
9
|
+
from prometheus_client import CollectorRegistry, Gauge, write_to_textfile
|
|
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 = []
|
|
78
|
+
for s in f.samples:
|
|
79
|
+
samples.append(s)
|
|
80
|
+
if len(samples) > 0:
|
|
81
|
+
# if we have samples, use the labelnames from them
|
|
82
|
+
labelnames = list(samples[0].labels.keys())
|
|
83
|
+
# metric-type specific init
|
|
84
|
+
if f.type == "gauge":
|
|
85
|
+
m = Gauge(
|
|
86
|
+
f.name,
|
|
87
|
+
f.documentation,
|
|
88
|
+
unit=f.unit,
|
|
89
|
+
labelnames=labelnames,
|
|
90
|
+
registry=self.registry,
|
|
91
|
+
)
|
|
92
|
+
else:
|
|
93
|
+
# we don't support other types yet, continue in these cases
|
|
94
|
+
self.logger.warning(
|
|
95
|
+
"unsupported metric type %s, dropping", f.type
|
|
96
|
+
)
|
|
97
|
+
continue
|
|
98
|
+
for s in samples:
|
|
99
|
+
if len(labelnames) > 0:
|
|
100
|
+
labelvalues = list(s.labels.values())
|
|
101
|
+
m.labels(*labelvalues).set(s.value)
|
|
102
|
+
else:
|
|
103
|
+
m.set(s.value)
|
|
104
|
+
self.metrics[f.name] = m
|
|
105
|
+
self.logger.info(
|
|
106
|
+
"copy gauge metric %s with labels %s from old file",
|
|
107
|
+
f.name,
|
|
108
|
+
", ".join(labelnames),
|
|
109
|
+
)
|
|
110
|
+
else:
|
|
111
|
+
self.logger.warning(
|
|
112
|
+
"got empty metric %s from old file, dropping", 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)
|
|
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!", la
|
|
150
|
+
)
|
|
151
|
+
sys.exit(1)
|
|
152
|
+
if len(old_labelnames) != len(labels.keys()):
|
|
153
|
+
self.logger.error(
|
|
154
|
+
"labelnames for metric %s not the same, cannot update! Old: %s, New: %s",
|
|
155
|
+
self.args.metric,
|
|
156
|
+
old_labelnames,
|
|
157
|
+
list(labels.keys()),
|
|
158
|
+
)
|
|
159
|
+
sys.exit(1)
|
|
160
|
+
self.logger.info("updating metric %s", self.args.metric)
|
|
161
|
+
|
|
162
|
+
# actually set the value
|
|
163
|
+
if len(labelvalues) > 0:
|
|
164
|
+
m.labels(*labelvalues).set(self.args.value)
|
|
165
|
+
else:
|
|
166
|
+
m.set(self.args.value)
|
|
167
|
+
|
|
168
|
+
def output_file(self):
|
|
169
|
+
"""Output to a textfile"""
|
|
170
|
+
write_to_textfile(self.textfile, self.registry)
|
|
171
|
+
self.logger.info("wrote to %s", self.textfile)
|
|
172
|
+
|
|
173
|
+
def cli_entrypoint(self):
|
|
174
|
+
"""Main method called from the CLI"""
|
|
175
|
+
self._arguments()
|
|
176
|
+
|
|
177
|
+
logging.basicConfig(level=self.args.loglevel)
|
|
178
|
+
self.logger = logging.getLogger(__name__)
|
|
179
|
+
|
|
180
|
+
self.parse_file()
|
|
181
|
+
self._build_metrics()
|
|
182
|
+
self.output_file()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: promtext-cli
|
|
3
|
-
Version: 0.1.2.
|
|
3
|
+
Version: 0.1.2.dev98
|
|
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=dSifo05hboJyEDbLv6F9u7ETNndlXmrRn_Ol8r4EEFk,208
|
|
3
|
+
promtext_cli/promtext.py,sha256=BhCZ8ZjyyxD680FeXiaPwU9jXCku4D8fVPRLbZv0_Mc,6402
|
|
4
|
+
promtext_cli-0.1.2.dev98.dist-info/METADATA,sha256=Y_VFIy0JR-yXiIedY5xoK6gpG81CIJj_cmL1lUdJFzQ,3414
|
|
5
|
+
promtext_cli-0.1.2.dev98.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
6
|
+
promtext_cli-0.1.2.dev98.dist-info/entry_points.txt,sha256=qH5Z6dM8QLK7tQ0RrdWZQtRcsdCyaGSU1WXygIcaRRc,52
|
|
7
|
+
promtext_cli-0.1.2.dev98.dist-info/RECORD,,
|
|
@@ -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.dev96.dist-info/METADATA,sha256=ksmp_99i-MyCAheZHgGE5saMFYTqIZKfHQANtAVFifk,3414
|
|
4
|
-
promtext_cli-0.1.2.dev96.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
5
|
-
promtext_cli-0.1.2.dev96.dist-info/entry_points.txt,sha256=mIY1sCmFCjCpCfn3px-BajeXOaKZIA7iR5_fCaUJ4gg,56
|
|
6
|
-
promtext_cli-0.1.2.dev96.dist-info/RECORD,,
|
|
File without changes
|