Skip to content

Commit f4aeee4

Browse files
committed
readme fixes, small improvements and todos
1 parent 8d8866c commit f4aeee4

File tree

6 files changed

+112
-33
lines changed

6 files changed

+112
-33
lines changed

README.md

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/gistart/prometheus-push-client/test-all)](https://github.com/gistart/prometheus-push-client/actions)
2-
[![Codecov](https://img.shields.io/codecov/c/github/gistart/prometheus-push-client)](https://codecov.io/gh/gistart/prometheus-push-client)
1+
[![test-all](https://github.com/gistart/prometheus-push-client/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/gistart/prometheus-push-client/actions)
2+
[![codecov](https://codecov.io/gh/gistart/prometheus-push-client/branch/master/graph/badge.svg?token=6K4G8CDU2R)](https://codecov.io/gh/gistart/prometheus-push-client)
33

44
# prometheus-push-client
55

6-
Push metrics from your regular and/or long-running jobs into existing Prometheus/VictoriaMetrics monitoring system.
6+
Push metrics from your regular and/or long-running jobs to existing Prometheus/VictoriaMetrics monitoring system.
77

8-
:no-entry: not tested in real environment yet!
8+
:no_entry: not tested in real environment yet!
99

10-
Currently supports pushes directly into VictoriaMetrics via UDP and HTTP using InfluxDB line protocol as [described here](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html?highlight=telegraf#how-to-send-data-from-influxdb-compatible-agents-such-as-telegraf), and into StatsD/statsd-exporter in StatsD format via UDP ([not ideal](https://github.com/prometheus/statsd_exporter#with-statsd)).
10+
Currently supports pushes directly to VictoriaMetrics via UDP and HTTP using InfluxDB line protocol as [described here](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html?highlight=telegraf#how-to-send-data-from-influxdb-compatible-agents-such-as-telegraf), and into StatsD/statsd-exporter in StatsD format via UDP ([not ideal](https://github.com/prometheus/statsd_exporter#with-statsd)).
1111

1212
## Default labelvalues
1313

14-
With regular prometheus_client we can define defaults for either none or all our labels with `labelvalues`, but that's not enough.
14+
With regular prometheus_client, defaults may be defined for either _none_ or _all_ the labels (with `labelvalues`), but that's not enough.
1515

16-
We probably want to define some defaults, like `hostname`, or more importantly, **if we use VictoriaMetrics cluster** we need to push label `VictoriaMetrics_AccountID=<int>` (usually 1) or else our metrics will be ignored!
16+
We probably want to define _some_ defaults, like `hostname`, or more importantly, **if we use VictoriaMetrics cluster**, we always need to push label `VictoriaMetrics_AccountID=<int>` (usually 1) or else our metrics will be ignored.
1717

1818
Following example shows how to use defaults, and how to override them if necessary.
1919

@@ -40,16 +40,15 @@ counter1.labels("non-default", "login").inc()
4040

4141
Metrics with no labels are initialized at creation time. This can have unpleasant side-effect: if we initialize lots of metrics not used in currently running job, background clients will have to push their non-changing values in every synchronization session.
4242

43-
To avoid that we'll have to properly isolate each task's metrics, which can be impossible or rather tricky, or we can create metrics with default, non-changing labels (like `hostname`). Such metrics will initialize on fisrt use (inc), and we'll be pusing only metrics we actually used!
44-
43+
To avoid that we'll have to properly isolate each task's metrics, which can be impossible or rather tricky, or we can create metrics with default, non-changing labels (like `hostname`). Such metrics will be initialized on fisrt use (inc), and we'll be pusing only those we actually used!
4544

4645
## Background clients
4746

48-
Background clients spawn synchronization jobs "in background" (meaning in thread or asyncio task) to periodially send all metrics from `ppc.PUSH_REGISTRY` to the destination.
47+
Background clients spawn synchronization jobs "in background" (meaning in a thread or asyncio task) to periodically send all metrics from `ppc.PUSH_REGISTRY` to the destination.
4948

50-
:warning: background clients will attempt to stop gracefully, syncronizing registry "for the last time" after our job exits or crashes. This _may_ mess up aggregation with sampling, I'm not sure yet.
49+
:warning: background clients will attempt to stop gracefully, synchronizing registry "one last time" after job exits or crashes. This _may_ mess up sampling aggregation, I'm not sure yet.
5150

52-
Best way to use them -- via decorators. These clients are intended to be used with long running, but finite tasks, that could be spawned anywhere, therefor not easily accessible by the scraper. If that's not the case -- just use "passive mode" w/ the scaper)
51+
Best way to use them is via decorators. These clients are intended to be used with long running, but finite tasks, which could be spawned anywhere, therefor not easily accessible by the scraper. If that's not the case -- just use "passive mode" w/ the scraper instead.
5352

5453
``` python
5554
def influx_udp_async(host, port, period=15.0):
@@ -61,8 +60,9 @@ def statsd_udp_thread(host, port, period=15.0):
6160
```
6261

6362
Usage example:
63+
6464
```python
65-
import priometheus_push_client as ppc
65+
import prometheus_push_client as ppc
6666

6767

6868
req_hist = ppc.Histogram(
@@ -74,10 +74,9 @@ req_hist = ppc.Histogram(
7474
)
7575

7676

77-
7877
@ppc.influx_udp_async("victoria.acme.inc.net", 9876, period=15)
7978
async def main(urls):
8079
# the job ...
8180
req_hist.labels(gethostname(url)).observe(response.elapsed)
8281
# ...
83-
```
82+
```

prometheus_push_client/clients/bg.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import asyncio
22
import threading
33
import time
4+
import logging
45

56
from prometheus_push_client import compat
67

78

9+
log = logging.getLogger("prometheus.bg")
10+
11+
812
class BackgroundClient:
913

1014
def __init__(self, format, transport, period=15.0, *args, **kwargs):
@@ -52,7 +56,7 @@ def run(self):
5256
try:
5357
self.transport.push_all(samples_iter)
5458
except Exception:
55-
pass # TODO log?
59+
log.error("push crashed", exc_info=True)
5660
period = self.period - (time.time() - ts_start)
5761

5862

@@ -86,5 +90,5 @@ async def run(self):
8690
try:
8791
await self.transport.push_all(samples_iter)
8892
except Exception:
89-
pass # TODO: log?
93+
log.error("push crashed", exc_info=True)
9094
period = self.period - (time.time() - ts_start)

prometheus_push_client/compat.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
if hasattr(asyncio, "get_running_loop"):
44
get_running_loop = asyncio.get_running_loop
55
else: # < 3.7, may be unsafe outside coroutines (running loop)
6-
get_running_loop = asyncio.get_event_loop
6+
get_running_loop = asyncio.get_event_loop # pragma: no cover
77

88

99
if hasattr(asyncio, "create_task"):
1010
create_task = asyncio.create_task
1111
else: # < 3.7, totally unsafe outside loop
12-
def create_task(coro):
12+
def create_task(coro): # pragma: no cover
1313
return asyncio.get_event_loop().create_task(coro)

prometheus_push_client/transports/udp.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ def push_one(self, data):
4242
raise NotImplementedError()
4343

4444

45+
# TODO: crashes on creation time DNS errors -- retry?
46+
47+
4548
class SyncUdpTransport(BaseUdpTransport):
4649
def start(self):
4750
self.transport = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

setup.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,43 @@
11
from distutils.core import setup
22

33

4+
# version
45
with open("./prometheus_push_client/version.py") as fd:
56
exec(fd.read())
67

8+
9+
# description
710
github_url = 'https://github.com/gistart/prometheus-push-client'
811

912
readme_lines = []
1013
with open('README.md') as fd:
1114
readme_lines = filter(None, fd.read().splitlines())
12-
readme_lines = list(readme_lines)[:3]
15+
readme_lines = list(readme_lines)[:5]
1316
readme_lines.append('Read more at [github page](%s).' % github_url)
1417
readme = '\n\n'.join(readme_lines)
1518

1619

20+
# requirements
21+
extras_require = {}
22+
extras_require["http"] = [
23+
"aiohttp<4",
24+
"requests<3",
25+
]
26+
extras_require["test"] = [
27+
"pytest",
28+
"pytest-asyncio",
29+
"pytest-cov",
30+
"pytest-mock",
31+
*extras_require["http"]
32+
]
33+
extras_require["dev"] = [
34+
"ipython",
35+
"twine",
36+
*extras_require["test"]
37+
]
38+
39+
40+
# setup
1741
setup(
1842
name="prometheus_push_client",
1943
version=__version__,
@@ -40,17 +64,5 @@
4064
install_requires=[
4165
"prometheus_client>=0.4.0",
4266
],
43-
extras_require={
44-
"http": [
45-
"aiohttp<4",
46-
"requests<3",
47-
],
48-
"test": [
49-
"pytest",
50-
"pytest-asyncio",
51-
"pytest-cov",
52-
"aiohttp<4",
53-
"requests<3",
54-
],
55-
}
67+
extras_require=extras_require,
5668
)

test/test_offline/test_misc.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import pytest
2+
import sys
3+
import time
4+
import asyncio
5+
import logging
6+
7+
import prometheus_push_client as ppc
8+
from prometheus_push_client import compat
9+
10+
11+
def test_missing_requests(mocker):
12+
mocker.patch("prometheus_push_client.transports.http.requests", None)
13+
with pytest.raises(RuntimeError):
14+
ppc.SyncHttpTransport("")
15+
16+
17+
def test_missing_aiohttp(mocker):
18+
mocker.patch("prometheus_push_client.transports.http.aiohttp", None)
19+
with pytest.raises(RuntimeError):
20+
ppc.AioHttpTransport("")
21+
22+
23+
def test_thread_client_transport_crash(mocker, caplog):
24+
mocker.patch(
25+
"prometheus_push_client.transports.udp.BaseUdpTransport.push_all",
26+
new=lambda *args, **kwargs: 1 / 0
27+
)
28+
29+
@ppc.influx_udp_thread("localhost", 9876, 0.1)
30+
def _test():
31+
for i in range(3):
32+
time.sleep(0.1)
33+
34+
with caplog.at_level(logging.INFO):
35+
_test()
36+
37+
assert any(
38+
lr.name == "prometheus.bg" and lr.msg == "push crashed"
39+
for lr in caplog.records
40+
)
41+
42+
43+
@pytest.mark.asyncio
44+
async def test_thread_client_transport_crash(mocker, caplog):
45+
mocker.patch(
46+
"prometheus_push_client.transports.udp.BaseUdpTransport.push_all",
47+
new=lambda *args, **kwargs: 1 / 0
48+
)
49+
50+
@ppc.influx_udp_async("localhost", 9876, 0.1)
51+
async def _test():
52+
for i in range(3):
53+
await asyncio.sleep(0.1)
54+
55+
with caplog.at_level(logging.INFO):
56+
await _test()
57+
58+
assert any(
59+
lr.name == "prometheus.bg" and lr.msg == "push crashed"
60+
for lr in caplog.records
61+
)

0 commit comments

Comments
 (0)