From 8e11a0153cf55d1b8339ecf6ee0ca4ae897af70a Mon Sep 17 00:00:00 2001 From: Aljaz Date: Mon, 2 Jun 2025 13:46:09 +0200 Subject: [PATCH] Switch metrics to Prometheus --- README.md | 5 +- requirements.txt | 3 +- .../RSSFeedProcessorLambda/src/metrics.py | 62 ++++++++++++------- 3 files changed, 47 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index ee7e2a3..872f402 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,10 @@ The primary goal of IngestRSS is to provide researchers with a robust, scalable ## 📊 Monitoring -The Lambda function logs its activities to CloudWatch Logs. You can monitor the function's performance and any errors through the AWS CloudWatch console. +The Lambda function logs are still sent to CloudWatch Logs, however metrics are +exposed using [Prometheus](https://prometheus.io/). When the processor runs it +starts a tiny HTTP server that serves metrics on `/metrics` (port `8000` by +default). These metrics can be scraped by a Prometheus server for monitoring. ## 🤝 Contributing diff --git a/requirements.txt b/requirements.txt index 4aeda36..e70b9df 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,5 @@ constructs==10.2.69 # Optional, yet necessary for the Pinecone SDK functionality. pinecone openai -tqdm \ No newline at end of file +tqdm +prometheus-client==0.20.* diff --git a/src/infra/lambdas/RSSFeedProcessorLambda/src/metrics.py b/src/infra/lambdas/RSSFeedProcessorLambda/src/metrics.py index 7766463..9d9fe1c 100644 --- a/src/infra/lambdas/RSSFeedProcessorLambda/src/metrics.py +++ b/src/infra/lambdas/RSSFeedProcessorLambda/src/metrics.py @@ -1,26 +1,46 @@ -import boto3 -import time +"""Prometheus metrics utilities for the RSS feed processor.""" -cloudwatch = boto3.client('cloudwatch') +import os +from prometheus_client import Counter, Histogram, start_http_server -def put_metric_data(metric_name, value, unit='Count'): - cloudwatch.put_metric_data( - Namespace='RSS/FeedProcessor', - MetricData=[ - { - 'MetricName': metric_name, - 'Value': value, - 'Unit': unit, - 'Timestamp': time.time() - }, - ] - ) -def record_processed_articles(count): - put_metric_data('ProcessedArticles', count) +# Start a Prometheus metrics HTTP server exposing ``/metrics``. The port can be +# customised with the ``METRICS_PORT`` environment variable. This block is safe +# to run multiple times as it silently ignores port binding errors. +_metrics_port = int(os.environ.get("METRICS_PORT", "8000")) +if not os.environ.get("METRICS_SERVER_STARTED"): + try: + start_http_server(_metrics_port) + os.environ["METRICS_SERVER_STARTED"] = "1" + except OSError: + pass -def record_processing_time(duration): - put_metric_data('ProcessingTime', duration, 'Seconds') -def record_extraction_errors(count): - put_metric_data('ExtractionErrors', count) \ No newline at end of file +# Metric definitions +_processed_articles = Counter( + "processed_articles_total", + "Total number of processed articles", +) +_processing_time = Histogram( + "rss_processing_seconds", + "Time spent processing RSS feeds", +) +_extraction_errors = Counter( + "extraction_errors_total", + "Number of article extraction errors", +) + + +def record_processed_articles(count: int) -> None: + """Increment the processed articles counter.""" + _processed_articles.inc(count) + + +def record_processing_time(duration: float) -> None: + """Record how long a feed took to process.""" + _processing_time.observe(duration) + + +def record_extraction_errors(count: int) -> None: + """Increment the extraction errors counter.""" + _extraction_errors.inc(count)