{"id":18266280,"url":"https://github.com/ssube/prometheus_express","last_synced_at":"2025-08-13T18:39:58.003Z","repository":{"id":36713259,"uuid":"202887941","full_name":"ssube/prometheus_express","owner":"ssube","description":"Prometheus SDK for CircuitPython/MicroPython boards","archived":false,"fork":false,"pushed_at":"2024-10-11T16:22:16.000Z","size":130,"stargazers_count":18,"open_issues_count":5,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-16T05:09:12.296Z","etag":null,"topics":["circuitpython","metrics","micropython","monitoring","prometheus","prometheus-exporter"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ssube.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-08-17T14:01:42.000Z","updated_at":"2024-10-23T12:23:35.000Z","dependencies_parsed_at":"2024-01-17T01:52:19.307Z","dependency_job_id":null,"html_url":"https://github.com/ssube/prometheus_express","commit_stats":{"total_commits":117,"total_committers":3,"mean_commits":39.0,"dds":"0.11111111111111116","last_synced_commit":"df74fb1584296ee4059d8627222185aa192756c5"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssube%2Fprometheus_express","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssube%2Fprometheus_express/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssube%2Fprometheus_express/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssube%2Fprometheus_express/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ssube","download_url":"https://codeload.github.com/ssube/prometheus_express/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247252542,"owners_count":20908711,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["circuitpython","metrics","micropython","monitoring","prometheus","prometheus-exporter"],"created_at":"2024-11-05T11:22:43.483Z","updated_at":"2025-04-04T21:32:36.048Z","avatar_url":"https://github.com/ssube.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# prometheus_express\n\nA [Prometheus](https://prometheus.io/) SDK for CircuitPython and MicroPython boards, helping integrate I2C and SPI\nsensors into existing Prometheus monitoring infrastructure.\n\n- only depends on `socket`\n- runs on CircuitPython 4.x and MicroPython for ESP32 and M0/M4 devices\n- runs even faster on CPython 3.x for local testing\n- API compatible with the official [prometheus/client_python](https://github.com/prometheus/client_python)\n- basic HTTP server with path/method routing\n- not terribly slow (20 rps on an ESP32, 50 rps on an M4 core, 5k on an i7 core)\n\nFor those unfamiliar with Prometheus, the examples expose an HTTP server on port `:8080` that serves `/metrics` in\na readable, plaintext format:\n\n```none\n# HELP prom_express_gas gas from the bme680 sensor\n# TYPE prom_express_gas gauge\nprom_express_gas 1060948\n# HELP prom_express_humidity humidity from both sensors\n# TYPE prom_express_humidity gauge\nprom_express_humidity{sensor=\"None\"} 0\nprom_express_humidity{sensor=\"bme680\"} 49.4062\nprom_express_humidity{sensor=\"si7021\"} 49.7976\n# HELP prom_express_pressure pressure from the bme680 sensor\n# TYPE prom_express_pressure gauge\nprom_express_pressure 983.25\n# HELP prom_express_temperature temperature from both sensors\n# TYPE prom_express_temperature gauge\nprom_express_temperature{sensor=\"None\"} 0\nprom_express_temperature{sensor=\"bme680\"} 24.7359\nprom_express_temperature{sensor=\"si7021\"} 24.3325\n```\n\nThe Prometheus server will occasionally scrape each device, collecting sensor readings with metadata about\ntheir source, and passing the samples on to [long-term storage](https://github.com/ssube/prometheus-sql-adapter/).\n\n## Contents\n\n- [prometheus_express](#prometheusexpress)\n  - [Contents](#contents)\n  - [Status](#status)\n  - [Releases](#releases)\n  - [Supported Hardware](#supported-hardware)\n  - [Supported Features](#supported-features)\n    - [HTTP Server](#http-server)\n    - [Metric Labels](#metric-labels)\n    - [Metric Types](#metric-types)\n      - [Counter](#counter)\n      - [Gauge](#gauge)\n      - [Summary](#summary)\n    - [Registries](#registries)\n  - [Planned Features](#planned-features)\n  - [Known Issues](#known-issues)\n    - [OSError 3, 4, or 7](#oserror-3-4-or-7)\n    - [OSError 112](#oserror-112)\n\n## Status\n\n[![Pipeline Status](https://git.apextoaster.com/ssube/prometheus_express/badges/master/pipeline.svg)](https://git.apextoaster.com/ssube/prometheus_express/commits/master)\n[![Test Coverage](https://codecov.io/gh/ssube/prometheus_express/branch/master/graph/badge.svg)](https://codecov.io/gh/ssube/prometheus_express)\n[![MIT license](https://img.shields.io/github/license/ssube/prometheus_express.svg)](https://github.com/ssube/prometheus_express/blob/master/LICENSE.md)\n\n[![Open bug count](https://img.shields.io/github/issues-raw/ssube/prometheus_express/type-bug.svg)](https://github.com/ssube/prometheus_express/issues?q=is%3Aopen+is%3Aissue+label%3Atype%2Fbug)\n[![Open issue count](https://img.shields.io/github/issues-raw/ssube/prometheus_express.svg)](https://github.com/ssube/prometheus_express/issues?q=is%3Aopen+is%3Aissue)\n[![Closed issue count](https://img.shields.io/github/issues-closed-raw/ssube/prometheus_express.svg)](https://github.com/ssube/prometheus_express/issues?q=is%3Aissue+is%3Aclosed)\n\n[![Maintainability](https://api.codeclimate.com/v1/badges/0b84df4baf76afa1b4c4/maintainability)](https://codeclimate.com/github/ssube/prometheus_express/maintainability)\n[![Technical debt ratio](https://img.shields.io/codeclimate/tech-debt/ssube/prometheus_express)](https://codeclimate.com/github/ssube/prometheus_express/trends/technical_debt)\n[![Quality issues](https://img.shields.io/codeclimate/issues/ssube/prometheus_express)](https://codeclimate.com/github/ssube/prometheus_express/issues)\n[![LGTM Language grade: Python](https://img.shields.io/lgtm/grade/python/g/ssube/prometheus_express.svg?logo=lgtm\u0026logoWidth=18)](https://lgtm.com/projects/g/ssube/prometheus_express/context:python)\n[![LGTM Total alerts](https://img.shields.io/lgtm/alerts/g/ssube/prometheus_express.svg?logo=lgtm\u0026logoWidth=18)](https://lgtm.com/projects/g/ssube/prometheus_express/alerts/)\n\n## Releases\n\n[![github release link](https://img.shields.io/badge/github-release-blue?logo=github)](https://github.com/ssube/prometheus_express/releases)\n[![github release version](https://img.shields.io/github/tag/ssube/prometheus_express.svg)](https://github.com/ssube/prometheus_express/releases)\n[![github commits since release](https://img.shields.io/github/commits-since/ssube/prometheus_express/v0.0.4.svg)](https://github.com/ssube/prometheus_express/compare/v0.0.4...master)\n\n[![PyPI release link](https://img.shields.io/badge/pypi-package-blue?logo=pypi)](https://github.com/ssube/prometheus_express/releases)\n[![PyPI release version](https://img.shields.io/pypi/v/prometheus_express?color=green)](https://pypi.org/project/prometheus-express/)\n\n## Supported Hardware\n\nThis library is tested on:\n\n- the [Adafruit Feather M4 Express](https://www.adafruit.com/product/3857) running MicroPython 4.1.0 or better,\n  with an [Adafruit Ethernet FeatherWing](https://www.adafruit.com/product/3201) attached (using the Wiznet5500\n  driver).\n- the [Olimex ESP32-POE](https://www.olimex.com/Products/IoT/ESP32/ESP32-POE/open-source-hardware) running\n  CircuitPython 1.12.0 or better, with wifi or wired ethernet (using the LAN8720 driver)\n\n## Supported Features\n\n### HTTP Server\n\nThis module implements a very rudimentary HTTP server that almost certainly violates some part of the spec.\nHowever, it works with Chrome, curl, and Prometheus itself. Depending on the platform, it may also work with\n`wrk` benchmarks ([known issues](#known-issues)).\n\n### Metric Labels\n\nLabels are stored and used to accumulate values. Missing labels are reported as `None`.\n\nIf a metric is constructed with labels, a default entry with all values set to `None` will also be reported.\n\n### Metric Types\n\n`Counter`, `Gauge`, and `Summary` are implemented with labels.\n\n#### Counter\n\nIncremental values. Implements `inc(value)` and `dec(value)`.\n\n#### Gauge\n\nAbsolute values. Extends [counter](#counter) with `set(value)`.\n\n#### Summary\n\nIndividual values. Prints count and total of `observe(value)`.\n\n### Registries\n\nRegistries may be created with a namespace: `CollectorRegistry(namespace='foo')`\n\nCall `registry.render()` to format metrics in Prometheus'\n[plain text exposition format](https://prometheus.io/docs/instrumenting/exposition_formats/#text-based-format):\n\n```none\n# HELP prom_express_test_counter a test counter\n# TYPE prom_express_test_counter counter\nprom_express_test_counter 1588\n# HELP prom_express_test_gauge a test gauge\n# TYPE prom_express_test_gauge gauge\nprom_express_test_gauge 3887\n```\n\nMetrics may be registered with multiple registries.\n\n## Planned Features\n\n- push support: `push_to_gateway`\n- remaining metric types: `Histogram`\n- tests for API compatibility\n\n## Known Issues\n\n### OSError 3, 4, or 7\n\nLoad testing the HTTP endpoint may cause one of a variety of `OSError`s, often `errno` 3, 4, or 7.\n\n[This is related to the Wiznet5500 driver](https://github.com/adafruit/circuitpython/issues/2073) for\nethernet FeatherWings, and may not appear on other devices:\n\n```shell\n\u003e ./wrk -c 1 -d 60s -t 1 http://server:8080/\nRunning 1m test @ http://server:8080/\n  1 threads and 1 connections\n    Thread Stats   Avg      Stdev     Max   +/- Stdev\n    Latency     8.64ms  485.57us  12.81ms   97.75%\n    Req/Sec   111.60      5.21   121.00     71.00%\n  2222 requests in 20.61s, 671.83KB read\n  Socket errors: connect 0, read 1, write 2743, timeout 0\nRequests/sec:    107.82\nTransfer/sec:     32.60KB\n```\n\nSome are fatal:\n\n```none\nConnection from ('client', 8080)\nAccepting...\nConnection from ('client', 8080)\nAccepting...\nError accepting request: [Errno 128] ENOTCONN\nBinding: server:8080\nTraceback (most recent call last):\n  File \"code.py\", line 90, in \u003cmodule\u003e\n  File \"code.py\", line 87, in main\n  File \"code.py\", line 87, in main\n  File \"code.py\", line 55, in bind\n  File \"/lib/prometheus_express/http.py\", line 11, in start_http_server\nOSError: 4\n```\n\nOthers require the socket to be rebound:\n\n```none\nConnection from ('client', 8080)\nAccepting...\nError accepting request: 7\nBinding: server:8080\nAccepting...\n```\n\n### OSError 112\n\nCertain crashes may leak open sockets, causing the device to log an `OSError 112` during startup.\n\nThe error prevents the HTTP server from binding to the ethernet device, so an HTTP watchdog on the\nswitch can be used to restart POE devices. The board can also be reset by calling `machine.reset()`\nfrom the REPL.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fssube%2Fprometheus_express","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fssube%2Fprometheus_express","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fssube%2Fprometheus_express/lists"}