Bring everything up-to-date

This commit is contained in:
Scott Wallace 2025-02-25 18:19:38 +00:00
parent 0042d2367a
commit c4fbfe53a3
Signed by: scott
SSH key fingerprint: SHA256:+LJug6Dj01Jdg86CILGng9r0lJseUrpI0xfRqdW9Uws
2 changed files with 78 additions and 82 deletions

View file

@ -1,20 +1,19 @@
FROM python:3.8-slim-buster
FROM python:3.11-alpine AS base
# Keeps Python from generating .pyc files in the container
ENV PYTHONDONTWRITEBYTECODE 1
# Turns off buffering for easier container logging
ENV PYTHONUNBUFFERED 1
FROM base AS build
ADD requirements.txt .
RUN python -m pip install -r requirements.txt
RUN python -m pip install --user -r requirements.txt
FROM base AS app
RUN adduser -h /app -D appuser
COPY --from=build --chown=appuser /root/.local /app/.local
WORKDIR /app
COPY main.py /app
RUN useradd appuser && chown -R appuser /app
COPY --chown=appuser main.py /app
USER appuser
FROM app
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
EXPOSE 5000
ENTRYPOINT ["python", "main.py"]

139
main.py
View file

@ -4,7 +4,7 @@ Present observational weather data to Prometheus
import json
import os
from typing import Dict, List, TypedDict
from typing import TypedDict
import requests
from flask import Flask, Response
@ -21,33 +21,28 @@ class PromData(TypedDict):
"""
key: str
labels: Dict[str, str]
labels: dict[str, str]
type: str
value: float
def fetch_weather_data(location: int, apikey: str) -> Dict[str, Dict[str, float]]:
def fetch_weather_data(location: str, apikey: str) -> dict[str, dict[str, float]]:
"""
Fetch current data from the Met Office for the provided postcode
"""
obs_data = requests.get(
f'http://api.weatherapi.com/v1/current.json?'
f'key={apikey}&'
f'q={location}&'
f'aqi=yes'
)
obs_data = requests.get(f"http://api.weatherapi.com/v1/current.json?key={apikey}&q={location}&aqi=yes", timeout=30)
return dict(json.loads(obs_data.content))
@app.route('/metrics')
@app.route("/metrics")
def metrics() -> Response:
"""
Output Prometheus-style metrics
"""
apikey = os.environ.get('WEATHER_APIKEY')
location = os.environ.get('WEATHER_LOCATION')
apikey = os.environ.get("WEATHER_APIKEY")
location = os.environ.get("WEATHER_LOCATION")
if not location:
return Response(
@ -55,88 +50,88 @@ def metrics() -> Response:
status=500,
)
latest_data = fetch_weather_data(int(location), str(apikey))['current']
latest_data = fetch_weather_data(location, str(apikey))["current"]
ret_data: List[PromData] = [
ret_data: list[PromData] = [
{
'key': 'sensor_weather_outdoor_temperature_celsius',
'labels': {
'location': location,
"key": "sensor_weather_outdoor_temperature_celsius",
"labels": {
"location": location,
},
'type': 'gauge',
'value': float(latest_data['temp_c']),
"type": "gauge",
"value": float(latest_data["temp_c"]),
},
{
'key': 'sensor_weather_outdoor_humidity_percent',
'labels': {
'location': location,
"key": "sensor_weather_outdoor_humidity_percent",
"labels": {
"location": location,
},
'type': 'gauge',
'value': float(latest_data['humidity']),
"type": "gauge",
"value": float(latest_data["humidity"]),
},
{
'key': 'sensor_weather_outdoor_uv',
'labels': {
'location': location,
"key": "sensor_weather_outdoor_uv",
"labels": {
"location": location,
},
'type': 'gauge',
'value': float(latest_data['uv']),
"type": "gauge",
"value": float(latest_data["uv"]),
},
{
'key': 'sensor_weather_outdoor_cloud_percent',
'labels': {
'location': location,
"key": "sensor_weather_outdoor_cloud_percent",
"labels": {
"location": location,
},
'type': 'gauge',
'value': float(latest_data['cloud']),
"type": "gauge",
"value": float(latest_data["cloud"]),
},
{
'key': 'sensor_weather_outdoor_precip',
'labels': {
'location': location,
"key": "sensor_weather_outdoor_precip",
"labels": {
"location": location,
},
'type': 'gauge',
'value': float(latest_data['precip_mm']),
"type": "gauge",
"value": float(latest_data["precip_mm"]),
},
{
'key': 'sensor_weather_outdoor_wind_speed',
'labels': {
'location': location,
"key": "sensor_weather_outdoor_wind_speed",
"labels": {
"location": location,
},
'type': 'gauge',
'value': float(latest_data['wind_kph']),
"type": "gauge",
"value": float(latest_data["wind_kph"]),
},
{
'key': 'sensor_weather_outdoor_wind_gust',
'labels': {
'location': location,
"key": "sensor_weather_outdoor_wind_gust",
"labels": {
"location": location,
},
'type': 'gauge',
'value': float(latest_data['gust_kph']),
"type": "gauge",
"value": float(latest_data["gust_kph"]),
},
{
'key': 'sensor_weather_outdoor_wind_direction',
'labels': {
'location': location,
"key": "sensor_weather_outdoor_wind_direction",
"labels": {
"location": location,
},
'type': 'gauge',
'value': float(latest_data['wind_degree']),
"type": "gauge",
"value": float(latest_data["wind_degree"]),
},
{
'key': 'sensor_weather_outdoor_temp_feel_c',
'labels': {
'location': location,
"key": "sensor_weather_outdoor_temp_feel_c",
"labels": {
"location": location,
},
'type': 'gauge',
'value': float(latest_data['feelslike_c']),
"type": "gauge",
"value": float(latest_data["feelslike_c"]),
},
{
'key': 'sensor_weather_outdoor_pressure',
'labels': {
'location': location,
"key": "sensor_weather_outdoor_pressure",
"labels": {
"location": location,
},
'type': 'gauge',
'value': float(latest_data['pressure_mb']),
"type": "gauge",
"value": float(latest_data["pressure_mb"]),
},
]
@ -146,17 +141,19 @@ def metrics() -> Response:
ret_strs.append(f'# TYPE {item["key"]} {item["type"]}')
ret_strs.append(
str(item["key"])
+ '{'
+ "{"
+ " ".join([f'{key}="{val}"' for key, val in item["labels"].items()])
+ '} '
+ str(item["value"])
+ "} "
+ str(
item["value"],
)
)
resp = Response('\n'.join(ret_strs))
resp.headers['Content-type'] = 'text/plain'
resp = Response("\n".join(ret_strs))
resp.headers["Content-type"] = "text/plain"
return resp
if __name__ == '__main__':
app.run(host='0.0.0.0')
if __name__ == "__main__":
app.run(host="0.0.0.0")