Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 68 additions & 16 deletions app_python/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,50 @@
Main application module
"""
import json
from flask import Flask, jsonify, request
from flask import Flask, Response, jsonify, request
from datetime import datetime, timezone
import logging
import os
import platform
import socket
from prometheus_client import Counter, Histogram, Gauge, generate_latest


HOST = os.getenv('HOST', '0.0.0.0')
PORT = int(os.getenv('PORT', 5000))
DEBUG = os.getenv('DEBUG', 'False').lower() == 'true'


class PrometheusStats:
http_requests_total: Counter
http_request_duration_seconds: Histogram
http_requests_in_progress: Gauge
system_info_duration_seconds: Histogram

def __init__(self):
self.http_requests_total = Counter(
'http_requests_total',
'Total HTTP requests',
['method', 'endpoint', 'status']
)
self.http_request_duration_seconds = Histogram(
'http_request_duration_seconds',
'HTTP request duration',
['method', 'endpoint']
)
self.http_requests_in_progress = Gauge(
'http_requests_in_progress',
'HTTP requests currently being processed'
)
self.system_info_duration_seconds = Histogram(
'system_info_duration_seconds',
'System stats collection time'
)


prometheus = PrometheusStats()


class JSONFormatter(logging.Formatter):
def __init__(self):
super().__init__()
Expand Down Expand Up @@ -92,27 +124,33 @@ def get_http_extra_info():


@app.route('/')
@prometheus.http_request_duration_seconds.labels('GET', '/').time()
@prometheus.http_requests_in_progress.track_inprogress()
def index():
"""Main endpoint - service and system information."""
logger.debug(f'Request: {request.method} {request.path}', extra=get_http_extra_info())
return jsonify({
'service': {
'name': 'devops-info-service',
'version': '1.0.0',
'description': 'DevOps course info service',
'framework': 'Flask'
},
'system': get_system_info(),
'runtime': get_uptime(),
'request': get_request_info(),
'endpoints': [
{"path": "/", "method": "GET", "description": "Service information"},
{"path": "/health", "method": "GET", "description": "Health check"}
]
})
with prometheus.system_info_duration_seconds.time():
response = {
'service': {
'name': 'devops-info-service',
'version': '1.0.0',
'description': 'DevOps course info service',
'framework': 'Flask'
},
'system': get_system_info(),
'runtime': get_uptime(),
'request': get_request_info(),
'endpoints': [
{"path": "/", "method": "GET", "description": "Service information"},
{"path": "/health", "method": "GET", "description": "Health check"}
]
}
return jsonify(response)


@app.route('/health')
@prometheus.http_request_duration_seconds.labels('GET', '/health').time()
@prometheus.http_requests_in_progress.track_inprogress()
def health():
logger.debug(f'Request: {request.method} {request.path}', extra=get_http_extra_info())
return jsonify({
Expand All @@ -122,6 +160,13 @@ def health():
})


@app.route('/metrics')
@prometheus.http_request_duration_seconds.labels('GET', '/metrics').time()
@prometheus.http_requests_in_progress.track_inprogress()
def metrics():
return Response(response=generate_latest(), status=200, content_type='text/plain')


@app.errorhandler(404)
def notfound_handler(e):
logger.info('A 404 Not Found error occured', extra=get_http_extra_info())
Expand All @@ -140,6 +185,13 @@ def internal_error(e):
}), 500


@app.after_request
def after_request(response: Response):
prometheus.http_requests_total.labels(request.method, request.path,
str(response.status_code)).inc()
return response


START_TIME = datetime.now(timezone.utc)
logger.info('Application starting... Configured with log level=%s', 'DEBUG' if DEBUG else 'INFO')
if __name__ == '__main__':
Expand Down
1 change: 1 addition & 0 deletions app_python/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
Flask==3.1.0
gunicorn==24.0.0
prometheus-client==0.23.1
42 changes: 32 additions & 10 deletions monitoring/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ services:
resources:
limits:
cpus: '1.0'
memory: 3G
memory: 1G
reservations:
cpus: '1'
memory: 1G
Expand Down Expand Up @@ -52,11 +52,8 @@ services:
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '1'
memory: 500M
cpus: '0.5'
memory: 512M
healthcheck:
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1"]
interval: 10s
Expand All @@ -76,12 +73,37 @@ services:
deploy:
resources:
limits:
cpus: '3.0'
memory: 4G
reservations:
cpus: '3'
cpus: '0.5'
memory: 256M
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:5000/health || exit 1"]
interval: 10s
timeout: 5s
retries: 5

prometheus:
image: prom/prometheus:v3.9.0
ports:
- 9090:9090
volumes:
- ${PWD}/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus:rw
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=15d'
- '--storage.tsdb.retention.size=10GB'
deploy:
resources:
limits:
memory: 1G
cpus: '1.0'
healthcheck:
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:9090/-/healthy || exit 1"]
interval: 10s
timeout: 5s
retries: 5

volumes:
loki-data:
grafana-data:
prometheus-data:
Binary file added monitoring/docs/L8t1_metrics_endpoint.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added monitoring/docs/L8t2_query.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added monitoring/docs/L8t2_targets_up.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added monitoring/docs/L8t3_custom_dashboard.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added monitoring/docs/L8t4_healthy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading