Skip to content

Commit 4d2b00d

Browse files
changes
Signed-off-by: Felipe Monteiro Jácome <[email protected]>
1 parent 7b70683 commit 4d2b00d

File tree

6 files changed

+122
-66
lines changed

6 files changed

+122
-66
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ dist
77
.coverage
88
.tox
99
.*cache
10-
htmlcov
10+
htmlcov
11+
env39/

prometheus_client/exposition.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,6 @@ def sample_line(line):
168168
return f'{line.name}{labelstr} {floatToGoString(line.value)}{timestamp}\n'
169169

170170
output = []
171-
output_string = ""
172171
for metric in registry.collect():
173172
try:
174173
mname = metric.name
@@ -187,6 +186,7 @@ def sample_line(line):
187186
mtype = 'histogram'
188187
elif mtype == 'unknown':
189188
mtype = 'untyped'
189+
# default encoder
190190
if 'encoder' not in vars(metric) or ('encoder' in vars(metric) and metric.encoder != 'pandas'):
191191
# normal calls
192192
output.append('# HELP {} {}\n'.format(
@@ -208,15 +208,16 @@ def sample_line(line):
208208
output.append(f'# TYPE {metric.name}{suffix} gauge\n')
209209
output.extend(lines)
210210
else:
211+
# pandas encoder
211212
output.append('# HELP {} {}\n'.format(
212213
mname, metric.documentation.replace('\\', r'\\').replace('\n', r'\n')))
213214
output.append(f'# TYPE {mname} {mtype}\n')
214-
import pdb; pdb.set_trace()
215+
output.extend(metric[metric._tag].to_list())
215216
except Exception as exception:
216217
exception.args = (exception.args or ('',)) + (metric,)
217218
raise
218-
219-
return ''.join(output).encode('utf-8')
219+
220+
return ''.join(output).encode('utf-8')
220221

221222

222223
def choose_encoder(accept_header):

prometheus_client/metrics.py

+32-46
Original file line numberDiff line numberDiff line change
@@ -739,13 +739,8 @@ def _raise_if_not_observable(self):
739739
def _is_parent(self):
740740
return self._labelnames and not self._labelvalues
741741

742-
def _get_metric(self):
743-
print("get_metric")
744-
return Metric(self._name, self._documentation, self._type, self._unit)
745-
746742
def describe(self):
747-
print("describe")
748-
return [self._get_metric()]
743+
return [self._metrics]
749744

750745
def collect(self):
751746
return [self._metrics]
@@ -758,66 +753,56 @@ def __repr__(self):
758753
metric_type = type(self)
759754
return f"{metric_type.__module__}.{metric_type.__name__}({self._name})"
760755

761-
def generate_pandas_report(self, value='value', tag='report'):
756+
def generate_pandas_report(self):
762757
def make_str(row):
763-
return f"{self._name}({[ f'{col}={row[col]}, ' for col in self._metrics.columns if col not in [value, tag]]})"
764-
765-
# generate another column with metric formated
766-
# make_str = lambda x: "metric01(a={}, b={})".format(x['a'],x['b'])
767-
# a = s.apply(make_str , axis=1)
768-
# https://github.com/prometheus/client_python/discussions/772
769-
770-
self._metrics[value] = self._metrics.apply(make_str, axis=1)
758+
return f"""{self._name}({','.join([ f'{col}={row[col]} ' for col in self._labelnames if col not in [self._value, self._tag]])}) {row[self._value]} {chr(10)}"""
759+
with self._lock:
760+
self._metrics[self._tag] = self._metrics.apply(make_str, axis=1)
771761
# self._metrics
772762

773763
def set_metric(self, df: pd.DataFrame):
774764
with self._lock:
765+
df.name = self._name
766+
df.type = self._type
767+
df.documentation = self._documentation
768+
df.encoder = 'pandas'
775769
self._metrics = df
776770
self.generate_pandas_report()
777-
import pdb; pdb.set_trace()
778-
779-
#def __init__(self: T,
780-
# name: str,
781-
# documentation: str,
782-
# labelnames: Iterable[str] = (),
783-
# namespace: str = '',
784-
# subsystem: str = '',
785-
# unit: str = '',
786-
# registry: Optional[CollectorRegistry] = REGISTRY,
787-
# _labelvalues: Optional[Sequence[str]] = None,
788-
# ) -> None:
771+
789772
def __init__(
790773
self: T,
791-
df: pd.DataFrame,
774+
name: str = '',
775+
documentation: str = '',
792776
namespace: str = '',
793777
subsystem: str = '',
794-
registry: Optional[CollectorRegistry] = REGISTRY
778+
unit: str = '',
779+
df=None,
780+
columns=None,
781+
registry: Optional[CollectorRegistry] = REGISTRY,
782+
tag='report',
783+
value='value'
795784
) -> None:
796785
"""
797786
Esta classe parte do pressuporto que a metrica é trocada com mais eficiencia do que ficar alterando apenas 1 valor
798787
o calculo pode ser feito em outro lugar e passar apenas a estrutura completo pronto em DataFrame
799788
"""
800-
if 'documentation' in vars(df):
801-
documentation = df.documentation
802-
else:
803-
documentation = 'no doc provided'
804-
if 'unit' in vars(df):
805-
unit = df.unit
806-
else:
807-
unit = 'no unit provided'
808-
if 'name' in vars(df):
809-
name = df.name
810-
else:
811-
name = 'no name provided'
812-
df.type = self._type
813-
df.encoder = self._encoder
814789
self._name = _build_full_name(self._type, name, namespace, subsystem, unit)
815-
self._labelnames = _validate_labelnames(self, df.columns)
790+
if columns:
791+
self._labelvalues = columns
792+
else:
793+
self._labelvalues = df.columns
794+
self._labelnames = _validate_labelnames(self, self._labelvalues)
816795
self._labelvalues = tuple(None or ())
817796
self._kwargs: Dict[str, Any] = {}
818797
self._documentation = documentation
819798
self._unit = unit
820-
799+
self._tag = tag
800+
self._value = value
801+
df.name = self._name
802+
df.type = self._type
803+
df.documentation = documentation
804+
df.encoder = self._encoder
805+
df._tag = tag
821806
if not METRIC_NAME_RE.match(self._name):
822807
raise ValueError('Invalid metric name: ' + self._name)
823808

@@ -826,14 +811,15 @@ def __init__(
826811
self._lock = Lock()
827812
self._metrics = df
828813

814+
829815
if self._is_observable():
830816
self._metric_init()
831817

832818
if not self._labelvalues:
833819
# Register the multi-wrapper parent metric, or if a label-less metric, the whole shebang.
834820
if registry:
835821
registry.register(self)
836-
822+
self.generate_pandas_report()
837823

838824
def remove(self, *labelvalues):
839825
if not self._labelnames:

requirements.txt

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pytest
2+
pandas

tests/test_exposition.py

+80-13
Original file line numberDiff line numberDiff line change
@@ -194,20 +194,87 @@ def collect(self):
194194
""", generate_latest(self.registry))
195195

196196
def test_gauge_pandas(self):
197-
df = pd.DataFrame({'a': [1.1,2.2,3.3,4.4], 'b':[5.1,6.2,7.3,8.4]})
198-
df.name = 'report_pandas'
199-
df.documentation = 'metric description'
200-
df.unit = ''
201-
df2 = pd.DataFrame({'c': [1.1,2.2,3.3,4.4], 'd':[5.1,6.2,7.3,8.4]})
202-
df2.name = 'report_panda2s'
203-
df2.documentation = 'metric description'
204-
df2.unit = ''
205-
g = PandasGauge(df, registry=self.registry)
206-
g = PandasGauge(df2, registry=self.registry)
207-
g.generate_pandas_report()
197+
"""
198+
2 possiveis chamadas
199+
usa apenas as colunas expostas
200+
PandasGauge('report_pandas', 'metric description', columns=['columnn01', 'column02'], registry=self.registry)
201+
ou
202+
usará todos as colunas
203+
PandasGauge('report_pandas', 'metric description', df=df, registry=self.registry)
204+
ou
205+
PandasGauge('report_pandas', 'metric description', df=df, columns=['columnn01', 'column02'], registry=self.registry)
206+
"""
207+
df = pd.DataFrame({'a': [1.1,2.2,3.3,4.4], 'b':[5.1,6.2,7.3,8.4], 'value': [1,2,3,4]})
208+
df2 = pd.DataFrame({'c': [1.1,2.2,3.3,4.4], 'd':[5.1,6.2,7.3,8.4], 'value': [5,6,7,8]})
209+
PandasGauge('report_pandas', 'metric description', df=df, columns= ['a', 'b', 'value'], registry=self.registry)
210+
g2 = PandasGauge('report_panda2s', 'metric description2', df=df2, registry=self.registry)
211+
212+
self.assertEqual(
213+
b'# HELP report_pandas metric description\n'
214+
b'# TYPE report_pandas gauge\n'
215+
b'report_pandas(a=1.1 ,b=5.1 ) 1.0 \n'
216+
b'report_pandas(a=2.2 ,b=6.2 ) 2.0 \n'
217+
b'report_pandas(a=3.3 ,b=7.3 ) 3.0 \n'
218+
b'report_pandas(a=4.4 ,b=8.4 ) 4.0 \n'
219+
b'# HELP report_panda2s metric description2\n'
220+
b'# TYPE report_panda2s gauge\n'
221+
b'report_panda2s(c=1.1 ,d=5.1 ) 5.0 \n'
222+
b'report_panda2s(c=2.2 ,d=6.2 ) 6.0 \n'
223+
b'report_panda2s(c=3.3 ,d=7.3 ) 7.0 \n'
224+
b'report_panda2s(c=4.4 ,d=8.4 ) 8.0 \n',
225+
generate_latest(self.registry)
226+
)
227+
228+
g2.set_metric(df2)
229+
self.assertEqual(
230+
b'# HELP report_pandas metric description\n'
231+
b'# TYPE report_pandas gauge\n'
232+
b'report_pandas(a=1.1 ,b=5.1 ) 1.0 \n'
233+
b'report_pandas(a=2.2 ,b=6.2 ) 2.0 \n'
234+
b'report_pandas(a=3.3 ,b=7.3 ) 3.0 \n'
235+
b'report_pandas(a=4.4 ,b=8.4 ) 4.0 \n'
236+
b'# HELP report_panda2s metric description2\n'
237+
b'# TYPE report_panda2s gauge\n'
238+
b'report_panda2s(c=1.1 ,d=5.1 ) 5 \n'
239+
b'report_panda2s(c=2.2 ,d=6.2 ) 6 \n'
240+
b'report_panda2s(c=3.3 ,d=7.3 ) 7 \n'
241+
b'report_panda2s(c=4.4 ,d=8.4 ) 8 \n',
242+
generate_latest(self.registry)
243+
)
244+
245+
def test_gauge_pandas_columns(self):
246+
"""
247+
2 possiveis chamadas
248+
usa apenas as colunas expostas
249+
PandasGauge('report_pandas', 'metric description', columns=['columnn01', 'column02'], registry=self.registry)
250+
ou
251+
usará todos as colunas
252+
PandasGauge('report_pandas', 'metric description', df=df, registry=self.registry)
253+
ou
254+
PandasGauge('report_pandas', 'metric description', df=df, columns=['columnn01', 'column02'], registry=self.registry)
255+
"""
256+
df = pd.DataFrame({'a': [1.1,2.2,3.3,4.4], 'b':[5.1,6.2,7.3,8.4], 'value': [1,2,3,4]})
257+
df2 = pd.DataFrame({'c': [1.1,2.2,3.3,4.4], 'd':[5.1,6.2,7.3,8.4], 'result': [5,6,7,8]})
258+
PandasGauge('report_pandas', 'metric description', df=df, columns= ['a', 'value'], registry=self.registry)
259+
g2 = PandasGauge('report_panda2s', 'metric description2', df=df2, columns=['d', 'result'],value='result' ,registry=self.registry)
260+
261+
208262
import pdb; pdb.set_trace()
209-
self.assertEqual(b'# HELP gg A gauge\n# TYPE gg gauge\ngg 17.0\n', generate_latest(self.registry))
210-
263+
self.assertEqual(
264+
b'# HELP report_pandas metric description\n'
265+
b'# TYPE report_pandas gauge\n'
266+
b'report_pandas(a=1.1 ) 1.0 \n'
267+
b'report_pandas(a=2.2 ) 2.0 \n'
268+
b'report_pandas(a=3.3 ) 3.0 \n'
269+
b'report_pandas(a=4.4 ) 4.0 \n'
270+
b'# HELP report_panda2s metric description2\n'
271+
b'# TYPE report_panda2s gauge\n'
272+
b'report_panda2s(d=5.1 ) 5.0 \n'
273+
b'report_panda2s(d=6.2 ) 6.0 \n'
274+
b'report_panda2s(d=7.3 ) 7.0 \n'
275+
b'report_panda2s(d=8.4 ) 8.0 \n',
276+
generate_latest(self.registry)
277+
)
211278

212279
class TestPushGateway(unittest.TestCase):
213280
def setUp(self):

tests/test_registry.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,4 @@ def test_collector_registry_gauge():
3232

3333
registry2 = CollectorRegistry()
3434
GP = PandasGauge('raid_status2', '1 if raid array is okay', ['label1'], registry=registry2)
35-
assert type(GP._metrics) == pd.core.frame.DataFrame
36-
import pdb; pdb.set_trace()
35+
assert type(GP._metrics) == pd.core.frame.DataFrame

0 commit comments

Comments
 (0)