Initial code commit

This commit is contained in:
Scott Wallace 2021-08-03 15:56:28 +01:00
commit d5a422ca10
Signed by: scott
GPG key ID: AA742FDC5AFE2A72
6 changed files with 117 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.vscode/
__pycache__/
.pyenv/

20
Dockerfile Normal file
View file

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

4
README.md Normal file
View file

@ -0,0 +1,4 @@
# Carbon Exporter
Pulls carbon intensity data from [carbonintensity.org.uk](https://carbonintensity.org.uk) and provides it in Prometheus-style exporter format over HTTP.
Used to monitor a UK region's carbon intensity over time.

9
docker-compose.yaml Normal file
View file

@ -0,0 +1,9 @@
---
version: '3.7'
services:
carbon-exporter:
image: carbon-exporter:latest
container_name: carbon-exporter
environment:
- CARBON_POSTCODE=<first 3 characters of UK postcode>
restart: unless-stopped

79
main.py Normal file
View file

@ -0,0 +1,79 @@
"""
Present observational weather data to Prometheus
"""
import json
import os
from typing import Dict, List
import requests # type: ignore
from flask import Flask, Response # type: ignore
app = Flask(__name__)
def fetch_carbon_data(postcode: str) -> Dict:
"""
Fetch current data for the carbon intensity of the provided region
"""
obs_data = requests.get(
f'https://api.carbonintensity.org.uk/regional/postcode/{postcode}'
)
return json.loads(obs_data.content)
@app.route('/metrics')
def metrics():
"""
Output Prometheus-style metrics
"""
postcode = os.environ.get('CARBON_POSTCODE')
latest_data = fetch_carbon_data(postcode)['data'][0]
ret_data: List = list()
for generation in latest_data['data'][0]['generationmix']:
ret_data.append(
{
'key': f'sensor_carbon_generation_{generation["fuel"]}_perc',
'labels': {
'region': latest_data['dnoregion'],
},
'type': 'gauge',
'value': float(generation['perc'])
}
)
ret_data.append(
{
'key': 'sensor_carbon_intensity_forecast',
'labels': {
'region': latest_data['dnoregion'],
},
'type': 'gauge',
'value': float(latest_data['data'][0]['intensity']['forecast']),
}
)
ret_strs = list()
for item in ret_data:
ret_strs.append(f'# HELP {item["key"]} Carbon metric')
ret_strs.append(f'# TYPE {item["key"]} {item["type"]}')
ret_strs.append(
item["key"]
+ '{'
+ " ".join([f'{key}="{val}"' for key, val in item["labels"].items()])
+ '} '
+ str(item["value"])
)
resp = Response('\n'.join(ret_strs))
resp.headers['Content-type'] = 'text/plain'
return resp
if __name__ == '__main__':
app.run(host='0.0.0.0')

2
requirements.txt Normal file
View file

@ -0,0 +1,2 @@
flask
requests