About Monitoring with Prometheus and Grafana

Both Prometheus and Grafana are compatible with microservice applications, integrating Prometheus with Flask is straightforward to provide performance and monitoring metrics.

Here I will update the docker-compose to add Prometheus and Grafana as services, then add Prometheus metrics in both order and user application code by importing PrometheusMetrics from the prometheus_flask_exporter module, which is used to expose Prometheus metrics for the Flask application. then initialize Prometheus metrics with metrics = PrometheusMetrics(app). Use @metrics.counter('get_orders_count', 'Count of calls to the get_orders endpoint') to define a Prometheus counter metric that increments each time the get_orders endpoint is called.

Import os to enable environment variable for Logstash host, logstash_host = os.getenv('LOGSTASH_HOST', 'localhost') to fetche the Logstash host from environment variables, defaulting to localhost.

# Folder structure
/06-with-monitoringstack
├── api_gateway
│   ├── api_gateway.py
│   └── Dockerfile
├── docker-compose.yml
├── logstash.conf
├── order_service
│   ├── Dockerfile
│   ├── order_service.py
├── prometheus.yaml
└── user_service
    ├── Dockerfile
    └── user_service.py

# add Prometheus and Grafana in docker-compose.yaml
version: '3'
services:
  prometheus:
    image: prom/prometheus
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"
  grafana:
    image: grafana/grafana
    ports:
      - "3000:3000"

# create prometheus.yml for Prometheus configration
# vim prometheus.yml
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'flask'
    static_configs:
      - targets: ['user-service:5001', 'order-service:5002']

# add Monitoring logic into python code 

# order_service.py
import logging
import requests
from flask import Flask, jsonify
from pygelf import GelfUdpHandler
from prometheus_flask_exporter import PrometheusMetrics
import os

app = Flask(__name__)
metrics = PrometheusMetrics(app)

@app.route('/orders')
def get_orders():
    orders = [
        {'id': 1, 'item': 'Laptop', 'price': 1200},
        {'id': 2, 'item': 'Phone', 'price': 800}
    ]
    app.logger.info("Fetched order data")
    return jsonify(orders)

def register_service():
    payload = {
        "ID": "order-service",
        "Name": "order-service",
        "Address": "order-service",
        "Port": 5002
    }
    response = requests.put('http://consul:8500/v1/agent/service/register', json=payload)
    if response.status_code == 200:
        app.logger.info("Order service registered successfully")
    else:
        app.logger.error("Failed to register order service")

if __name__ == '__main__':
    # Configure logging
    logstash_host = os.getenv('LOGSTASH_HOST', 'localhost')
    handler = GelfUdpHandler(host=logstash_host, port=12201)
    app.logger.addHandler(handler)
    app.logger.setLevel(logging.INFO)
    
    register_service()
    app.run(host='0.0.0.0', port=5002)


# user_service.py
import logging
import requests
from flask import Flask, jsonify
from pygelf import GelfUdpHandler
from prometheus_flask_exporter import PrometheusMetrics
import os

app = Flask(__name__)
metrics = PrometheusMetrics(app)

@app.route('/users')
def get_users():
    users = [
        {'id': 1, 'name': 'Alice'},
        {'id': 2, 'name': 'Bob'}
    ]
    app.logger.info("Fetched user data")
    return jsonify(users)

def register_service():
    payload = {
        "ID": "user-service",
        "Name": "user-service",
        "Address": "user-service",
        "Port": 5001
    }
    response = requests.put('http://consul:8500/v1/agent/service/register', json=payload)
    if response.status_code == 200:
        app.logger.info("User service registered successfully")
    else:
        app.logger.error("Failed to register user service")

if __name__ == '__main__':
    # Configure logging
    logstash_host = os.getenv('LOGSTASH_HOST', 'localhost')
    handler = GelfUdpHandler(host=logstash_host, port=12201)
    app.logger.addHandler(handler)
    app.logger.setLevel(logging.INFO)
    
    register_service()
    app.run(host='0.0.0.0', port=5001)

Now Run docker-compose to bring all containers up and running. Should see all services with Prometheus and Grafana.

docker-compose up --build

Creating 06-with-monitoringstack_api-gateway_1   ... done
Creating 06-with-monitoringstack_order-service_1 ... done
Creating 06-with-monitoringstack_user-service_1  ... done
Creating 06-with-monitoringstack_kibana_1        ... done
Creating 06-with-monitoringstack_grafana_1       ... done
Creating 06-with-monitoringstack_logstash_1      ... done
Creating 06-with-monitoringstack_prometheus_1    ... done
Creating 06-with-monitoringstack_elasticsearch_1 ... done
Creating 06-with-monitoringstack_consul_1        ... done

Verify Prometheus and Grafana

Access Grafana via http://localhost:3000, log in with admin/admin.

Add Prometheus as a Data Source in Grafana by setting the URL to http://localhost:9090 and save.

Create Dashboards in Grafana to use the Prometheus data source to visualize metrics from user-service and order-service.

image tooltip here

image tooltip here

Conclusion

Now we can enable monitoring with Prometheus and Grafana.

In the next post, I will see how to depoly our Python Flask microservice into Kubernetes.