Skip to content

Commit 2ef7e2a

Browse files
ajustes
Signed-off-by: Felipe Monteiro Jácome <[email protected]>
1 parent 5b3c767 commit 2ef7e2a

File tree

5 files changed

+106
-232
lines changed

5 files changed

+106
-232
lines changed

prometheus_client/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
write_to_textfile,
1212
)
1313
from .gc_collector import GC_COLLECTOR, GCCollector
14-
from .metrics import Counter, Enum, Gauge, Histogram, Info, Summary
14+
from .metrics import Counter, Enum, Gauge, Histogram, Info, Summary, PandasGauge
1515
from .metrics_core import Metric
1616
from .platform_collector import PLATFORM_COLLECTOR, PlatformCollector
1717
from .process_collector import PROCESS_COLLECTOR, ProcessCollector
@@ -27,6 +27,7 @@
2727
'Histogram',
2828
'Info',
2929
'Enum',
30+
'PandasGauge',
3031
'CONTENT_TYPE_LATEST',
3132
'generate_latest',
3233
'MetricsHandler',

prometheus_client/exposition.py

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -186,30 +186,39 @@ def sample_line(line):
186186
mtype = 'histogram'
187187
elif mtype == 'unknown':
188188
mtype = 'untyped'
189-
190-
output.append('# HELP {} {}\n'.format(
191-
mname, metric.documentation.replace('\\', r'\\').replace('\n', r'\n')))
192-
output.append(f'# TYPE {mname} {mtype}\n')
193-
194-
om_samples = {}
195-
for s in metric.samples:
196-
for suffix in ['_created', '_gsum', '_gcount']:
197-
if s.name == metric.name + suffix:
198-
# OpenMetrics specific sample, put in a gauge at the end.
199-
om_samples.setdefault(suffix, []).append(sample_line(s))
200-
break
201-
else:
202-
output.append(sample_line(s))
189+
import pdb; pdb.set_trace()
190+
if 'encoder' not in vars(metric) or ('encoder' in vars(metric) and metric.encoder != 'pandas'):
191+
# normal calls
192+
output.append('# HELP {} {}\n'.format(
193+
mname, metric.documentation.replace('\\', r'\\').replace('\n', r'\n')))
194+
output.append(f'# TYPE {mname} {mtype}\n')
195+
196+
om_samples = {}
197+
for s in metric.samples:
198+
for suffix in ['_created', '_gsum', '_gcount']:
199+
if s.name == metric.name + suffix:
200+
# OpenMetrics specific sample, put in a gauge at the end.
201+
om_samples.setdefault(suffix, []).append(sample_line(s))
202+
break
203+
else:
204+
output.append(sample_line(s))
205+
for suffix, lines in sorted(om_samples.items()):
206+
output.append('# HELP {}{} {}\n'.format(metric.name, suffix,
207+
metric.documentation.replace('\\', r'\\').replace('\n', r'\n')))
208+
output.append(f'# TYPE {metric.name}{suffix} gauge\n')
209+
output.extend(lines)
210+
else:
211+
output.append('# HELP {} {}\n'.format(
212+
mname, metric.documentation.replace('\\', r'\\').replace('\n', r'\n')))
213+
output.append(f'# TYPE {mname} {mtype}\n')
214+
import pdb; pdb.set_trace()
203215
except Exception as exception:
204216
exception.args = (exception.args or ('',)) + (metric,)
205217
raise
218+
import pdb; pdb.set_trace()
219+
206220

207-
for suffix, lines in sorted(om_samples.items()):
208-
output.append('# HELP {}{} {}\n'.format(metric.name, suffix,
209-
metric.documentation.replace('\\', r'\\').replace('\n', r'\n')))
210-
output.append(f'# TYPE {metric.name}{suffix} gauge\n')
211-
output.extend(lines)
212-
return ''.join(output).encode('utf-8')
221+
return ''.join(output).encode('utf-8')
213222

214223

215224
def choose_encoder(accept_header):

prometheus_client/metrics.py

Lines changed: 54 additions & 207 deletions
Original file line numberDiff line numberDiff line change
@@ -718,8 +718,9 @@ def _child_samples(self) -> Iterable[Sample]:
718718
]
719719

720720

721-
class MetricPandasWrapperBase:
722-
_type: Optional[str] = None
721+
class PandasGauge:
722+
_encoder = 'pandas'
723+
_type: Optional[str] = 'gauge'
723724
_reserved_labelnames: Sequence[str] = ()
724725

725726
def _is_observable(self):
@@ -739,37 +740,62 @@ def _is_parent(self):
739740
return self._labelnames and not self._labelvalues
740741

741742
def _get_metric(self):
743+
print("get_metric")
742744
return Metric(self._name, self._documentation, self._type, self._unit)
743745

744746
def describe(self):
747+
print("describe")
745748
return [self._get_metric()]
746749

747750
def collect(self):
748-
metric = self._get_metric()
749-
for suffix, labels, value, timestamp, exemplar in self._samples():
750-
metric.add_sample(self._name + suffix, labels, value, timestamp, exemplar)
751-
return [metric]
751+
return [self._metrics]
752752

753753
def __str__(self):
754754
return f"{self._type}:{self._name}"
755755

756756
def __repr__(self):
757+
print("repr")
757758
metric_type = type(self)
758759
return f"{metric_type.__module__}.{metric_type.__name__}({self._name})"
759760

760-
def __init__(self: T,
761-
name: str,
762-
documentation: str,
763-
labelnames: Iterable[str] = (),
764-
namespace: str = '',
765-
subsystem: str = '',
766-
unit: str = '',
767-
registry: Optional[CollectorRegistry] = REGISTRY,
768-
_labelvalues: Optional[Sequence[str]] = None,
769-
) -> None:
761+
#def __init__(self: T,
762+
# name: str,
763+
# documentation: str,
764+
# labelnames: Iterable[str] = (),
765+
# namespace: str = '',
766+
# subsystem: str = '',
767+
# unit: str = '',
768+
# registry: Optional[CollectorRegistry] = REGISTRY,
769+
# _labelvalues: Optional[Sequence[str]] = None,
770+
# ) -> None:
771+
def __init__(
772+
self: T,
773+
df: pd.DataFrame,
774+
namespace: str = '',
775+
subsystem: str = '',
776+
registry: Optional[CollectorRegistry] = REGISTRY
777+
) -> None:
778+
"""
779+
Esta classe parte do pressuporto que a metrica é trocada com mais eficiencia do que ficar alterando apenas 1 valor
780+
o calculo pode ser feito em outro lugar e passar apenas a estrutura completo pronto em DataFrame
781+
"""
782+
if 'documentation' in vars(df):
783+
documentation = df.documentation
784+
else:
785+
documentation = 'no doc provided'
786+
if 'unit' in vars(df):
787+
unit = df.unit
788+
else:
789+
unit = 'no unit provided'
790+
if 'name' in vars(df):
791+
name = df.name
792+
else:
793+
name = 'no name provided'
794+
df.type = self._type
795+
df.encoder = self._encoder
770796
self._name = _build_full_name(self._type, name, namespace, subsystem, unit)
771-
self._labelnames = _validate_labelnames(self, labelnames)
772-
self._labelvalues = tuple(_labelvalues or ())
797+
self._labelnames = _validate_labelnames(self, df.columns)
798+
self._labelvalues = tuple(None or ())
773799
self._kwargs: Dict[str, Any] = {}
774800
self._documentation = documentation
775801
self._unit = unit
@@ -780,7 +806,7 @@ def __init__(self: T,
780806
if self._is_parent():
781807
# Prepare the fields needed for child metrics.
782808
self._lock = Lock()
783-
self._metrics = pd.DataFrame(columns=labelnames)
809+
self._metrics = df
784810

785811
if self._is_observable():
786812
self._metric_init()
@@ -790,60 +816,6 @@ def __init__(self: T,
790816
if registry:
791817
registry.register(self)
792818

793-
def labels(self: T, *labelvalues: Any, **labelkwargs: Any) -> T:
794-
"""Return the child for the given labelset.
795-
796-
All metrics can have labels, allowing grouping of related time series.
797-
Taking a counter as an example:
798-
799-
from prometheus_client import Counter
800-
801-
c = Counter('my_requests_total', 'HTTP Failures', ['method', 'endpoint'])
802-
c.labels('get', '/').inc()
803-
c.labels('post', '/submit').inc()
804-
805-
Labels can also be provided as keyword arguments:
806-
807-
from prometheus_client import Counter
808-
809-
c = Counter('my_requests_total', 'HTTP Failures', ['method', 'endpoint'])
810-
c.labels(method='get', endpoint='/').inc()
811-
c.labels(method='post', endpoint='/submit').inc()
812-
813-
See the best practices on [naming](http://prometheus.io/docs/practices/naming/)
814-
and [labels](http://prometheus.io/docs/practices/instrumentation/#use-labels).
815-
"""
816-
if not self._labelnames:
817-
raise ValueError('No label names were set when constructing %s' % self)
818-
819-
if self._labelvalues:
820-
raise ValueError('{} already has labels set ({}); can not chain calls to .labels()'.format(
821-
self,
822-
dict(zip(self._labelnames, self._labelvalues))
823-
))
824-
825-
if labelvalues and labelkwargs:
826-
raise ValueError("Can't pass both *args and **kwargs")
827-
828-
if labelkwargs:
829-
if sorted(labelkwargs) != sorted(self._labelnames):
830-
raise ValueError('Incorrect label names')
831-
labelvalues = tuple(str(labelkwargs[l]) for l in self._labelnames)
832-
else:
833-
if len(labelvalues) != len(self._labelnames):
834-
raise ValueError('Incorrect label count')
835-
labelvalues = tuple(str(l) for l in labelvalues)
836-
with self._lock:
837-
if labelvalues not in self._metrics:
838-
self._metrics[labelvalues] = self.__class__(
839-
self._name,
840-
documentation=self._documentation,
841-
labelnames=self._labelnames,
842-
unit=self._unit,
843-
_labelvalues=labelvalues,
844-
**self._kwargs
845-
)
846-
return self._metrics[labelvalues]
847819

848820
def remove(self, *labelvalues):
849821
if not self._labelnames:
@@ -868,12 +840,13 @@ def _samples(self) -> Iterable[Sample]:
868840
return self._child_samples()
869841

870842
def _multi_samples(self) -> Iterable[Sample]:
871-
with self._lock:
872-
metrics = self._metrics.copy()
873-
for labels, metric in metrics.items():
874-
series_labels = list(zip(self._labelnames, labels))
875-
for suffix, sample_labels, value, timestamp, exemplar in metric._samples():
876-
yield Sample(suffix, dict(series_labels + list(sample_labels.items())), value, timestamp, exemplar)
843+
if 'pandas' not in vars(metrics._encoder):
844+
with self._lock:
845+
metrics = self._metrics.copy()
846+
for labels, metric in metrics.items():
847+
series_labels = list(zip(self._labelnames, labels))
848+
for suffix, sample_labels, value, timestamp, exemplar in metric._samples():
849+
yield Sample(suffix, dict(series_labels + list(sample_labels.items())), value, timestamp, exemplar)
877850

878851
def _child_samples(self) -> Iterable[Sample]: # pragma: no cover
879852
raise NotImplementedError('_child_samples() must be implemented by %r' % self)
@@ -883,132 +856,6 @@ def _metric_init(self): # pragma: no cover
883856
Initialize the metric object as a child, i.e. when it has labels (if any) set.
884857
885858
This is factored as a separate function to allow for deferred initialization.
859+
# raise NotImplementedError('_metric_init() must be implemented by %r' % self)
886860
"""
887-
raise NotImplementedError('_metric_init() must be implemented by %r' % self)
888-
889-
890-
class GaugePandas(MetricPandasWrapperBase):
891-
"""Gauge metric, to report instantaneous values.
892-
893-
Examples of Gauges include:
894-
- Inprogress requests
895-
- Number of items in a queue
896-
- Free memory
897-
- Total memory
898-
- Temperature
899-
900-
Gauges can go both up and down.
901-
902-
from prometheus_client import Gauge
903-
904-
g = Gauge('my_inprogress_requests', 'Description of gauge')
905-
g.inc() # Increment by 1
906-
g.dec(10) # Decrement by given value
907-
g.set(4.2) # Set to a given value
908-
909-
There are utilities for common use cases:
910-
911-
g.set_to_current_time() # Set to current unixtime
912-
913-
# Increment when entered, decrement when exited.
914-
@g.track_inprogress()
915-
def f():
916-
pass
917-
918-
with g.track_inprogress():
919-
pass
920-
921-
A Gauge can also take its value from a callback:
922-
923-
d = Gauge('data_objects', 'Number of objects')
924-
my_dict = {}
925-
d.set_function(lambda: len(my_dict))
926-
"""
927-
_type = 'gauge'
928-
_MULTIPROC_MODES = frozenset(('min', 'max', 'livesum', 'liveall', 'all'))
929-
930-
def __init__(self,
931-
name: str,
932-
documentation: str,
933-
labelnames: Iterable[str] = (),
934-
namespace: str = '',
935-
subsystem: str = '',
936-
unit: str = '',
937-
registry: Optional[CollectorRegistry] = REGISTRY,
938-
_labelvalues: Optional[Sequence[str]] = None,
939-
multiprocess_mode: str = 'all',
940-
):
941-
self._multiprocess_mode = multiprocess_mode
942-
if multiprocess_mode not in self._MULTIPROC_MODES:
943-
raise ValueError('Invalid multiprocess mode: ' + multiprocess_mode)
944-
super().__init__(
945-
name=name,
946-
documentation=documentation,
947-
labelnames=labelnames,
948-
namespace=namespace,
949-
subsystem=subsystem,
950-
unit=unit,
951-
registry=registry,
952-
_labelvalues=_labelvalues,
953-
)
954-
self._kwargs['multiprocess_mode'] = self._multiprocess_mode
955-
956-
def _metric_init(self) -> None:
957-
self._value = values.ValueClass(
958-
self._type, self._name, self._name, self._labelnames, self._labelvalues,
959-
multiprocess_mode=self._multiprocess_mode
960-
)
961-
962-
def inc(self, amount: float = 1) -> None:
963-
"""Increment gauge by the given amount."""
964-
self._raise_if_not_observable()
965-
self._value.inc(amount)
966-
967-
def dec(self, amount: float = 1) -> None:
968-
"""Decrement gauge by the given amount."""
969-
self._raise_if_not_observable()
970-
self._value.inc(-amount)
971-
972-
def set(self, value: float) -> None:
973-
"""Set gauge to the given value."""
974-
self._raise_if_not_observable()
975-
self._value.set(float(value))
976-
977-
def set_to_current_time(self) -> None:
978-
"""Set gauge to the current unixtime."""
979-
self.set(time.time())
980-
981-
def track_inprogress(self) -> InprogressTracker:
982-
"""Track inprogress blocks of code or functions.
983-
984-
Can be used as a function decorator or context manager.
985-
Increments the gauge when the code is entered,
986-
and decrements when it is exited.
987-
"""
988-
self._raise_if_not_observable()
989-
return InprogressTracker(self)
990-
991-
def time(self) -> Timer:
992-
"""Time a block of code or function, and set the duration in seconds.
993-
994-
Can be used as a function decorator or context manager.
995-
"""
996-
return Timer(self, 'set')
997-
998-
def set_function(self, f: Callable[[], float]) -> None:
999-
"""Call the provided function to return the Gauge value.
1000-
1001-
The function must return a float, and may be called from
1002-
multiple threads. All other methods of the Gauge become NOOPs.
1003-
"""
1004-
1005-
self._raise_if_not_observable()
1006-
1007-
def samples(_: Gauge) -> Iterable[Sample]:
1008-
return (Sample('', {}, float(f()), None, None),)
1009-
1010-
self._child_samples = types.MethodType(samples, self) # type: ignore
1011-
1012-
def _child_samples(self) -> Iterable[Sample]:
1013-
return (Sample('', {}, self._value.get(), None, None),)
1014-
861+
pass

0 commit comments

Comments
 (0)