|
1 | | -"""Demonstration of Prometheus metrics exporter for cachier. |
| 1 | +"""Prometheus Exporter Example for Cachier. |
2 | 2 |
|
3 | | -This example shows how to export cachier metrics to Prometheus for monitoring. The exporter can work with or without the |
4 | | -prometheus_client library. |
| 3 | +This example demonstrates using the PrometheusExporter to export cache metrics |
| 4 | +to Prometheus for monitoring and alerting. |
5 | 5 |
|
6 | | -""" |
7 | | - |
8 | | -import time |
9 | | - |
10 | | -from cachier import cachier |
11 | | -from cachier.exporters import PrometheusExporter |
| 6 | +Usage with Prometheus |
| 7 | +--------------------- |
12 | 8 |
|
13 | | -print("=" * 60) |
14 | | -print("Cachier Prometheus Exporter Demo") |
15 | | -print("=" * 60) |
16 | | - |
17 | | - |
18 | | -# Define some cached functions with metrics enabled |
19 | | -@cachier(backend="memory", enable_metrics=True) |
20 | | -def calculate_square(x): |
21 | | - """Calculate square of a number.""" |
22 | | - time.sleep(0.01) # Simulate computation |
23 | | - return x**2 |
24 | | - |
25 | | - |
26 | | -@cachier(backend="memory", enable_metrics=True) |
27 | | -def calculate_cube(x): |
28 | | - """Calculate cube of a number.""" |
29 | | - time.sleep(0.01) # Simulate computation |
30 | | - return x**3 |
31 | | - |
32 | | - |
33 | | -# Create a Prometheus exporter |
34 | | -# Set use_prometheus_client=False to use built-in text format |
35 | | -exporter = PrometheusExporter(port=9100, use_prometheus_client=False) |
36 | | - |
37 | | -# Register functions to export |
38 | | -print("\nRegistering functions with exporter...") |
39 | | -exporter.register_function(calculate_square) |
40 | | -exporter.register_function(calculate_cube) |
41 | | -print("✓ Functions registered") |
42 | | - |
43 | | -# Generate some cache activity |
44 | | -print("\nGenerating cache activity...") |
45 | | -calculate_square.clear_cache() |
46 | | -calculate_cube.clear_cache() |
47 | | - |
48 | | -# Create some metrics |
49 | | -for i in range(20): |
50 | | - calculate_square(i % 5) # Will create hits and misses |
51 | | - |
52 | | -for i in range(15): |
53 | | - calculate_cube(i % 3) |
54 | | - |
55 | | -print("✓ Generated activity on both functions") |
56 | | - |
57 | | -# Display metrics for each function |
58 | | -print("\n" + "=" * 60) |
59 | | -print("Metrics Summary") |
60 | | -print("=" * 60) |
61 | | - |
62 | | -square_stats = calculate_square.metrics.get_stats() |
63 | | -print("\ncalculate_square:") |
64 | | -print(f" Hits: {square_stats.hits}") |
65 | | -print(f" Misses: {square_stats.misses}") |
66 | | -print(f" Hit rate: {square_stats.hit_rate:.1f}%") |
67 | | -print(f" Total calls: {square_stats.total_calls}") |
68 | | - |
69 | | -cube_stats = calculate_cube.metrics.get_stats() |
70 | | -print("\ncalculate_cube:") |
71 | | -print(f" Hits: {cube_stats.hits}") |
72 | | -print(f" Misses: {cube_stats.misses}") |
73 | | -print(f" Hit rate: {cube_stats.hit_rate:.1f}%") |
74 | | -print(f" Total calls: {cube_stats.total_calls}") |
75 | | - |
76 | | -# Generate Prometheus text format |
77 | | -print("\n" + "=" * 60) |
78 | | -print("Prometheus Text Format Export") |
79 | | -print("=" * 60) |
80 | | - |
81 | | -metrics_text = exporter._generate_text_metrics() |
82 | | -print("\nSample of exported metrics:") |
83 | | -print("-" * 60) |
84 | | -# Print first 20 lines |
85 | | -lines = metrics_text.split("\n")[:20] |
86 | | -for line in lines: |
87 | | - print(line) |
88 | | -print("...") |
89 | | -print(f"\nTotal lines exported: {len(metrics_text.split(chr(10)))}") |
90 | | - |
91 | | -# Instructions for using with Prometheus |
92 | | -print("\n" + "=" * 60) |
93 | | -print("Usage with Prometheus") |
94 | | -print("=" * 60) |
95 | | -print(""" |
96 | 9 | To use this exporter with Prometheus: |
97 | 10 |
|
98 | 11 | 1. Start the exporter HTTP server: |
99 | 12 | >>> exporter.start() |
100 | 13 |
|
101 | | -2. Add to your prometheus.yml: |
| 14 | +2. Configure Prometheus to scrape the metrics endpoint. |
| 15 | + Add this to your prometheus.yml: |
| 16 | +
|
102 | 17 | scrape_configs: |
103 | 18 | - job_name: 'cachier' |
104 | 19 | static_configs: |
105 | | - - targets: ['localhost:9100'] |
106 | | -
|
107 | | -3. Access metrics at http://localhost:9100/metrics |
108 | | -
|
109 | | -4. Query in Prometheus: |
110 | | - - cachier_cache_hit_rate |
111 | | - - rate(cachier_cache_hits_total[5m]) |
112 | | - - cachier_entry_count |
113 | | -
|
114 | | -Alternative: Use with prometheus_client |
115 | | ---------------------------------------- |
116 | | -If you have prometheus_client installed: |
117 | | -
|
118 | | ->>> from prometheus_client import start_http_server |
119 | | ->>> exporter = PrometheusExporter(port=9100, use_prometheus_client=True) |
120 | | ->>> exporter.register_function(my_cached_func) |
121 | | ->>> exporter.start() |
122 | | -
|
123 | | -This provides additional features like: |
124 | | -- Automatic metric registration |
125 | | -- Built-in histograms |
126 | | -- Gauges and counters |
127 | | -- Integration with Prometheus pushgateway |
128 | | -""") |
129 | | - |
130 | | -print("\n" + "=" * 60) |
131 | | -print("Demo Complete") |
132 | | -print("=" * 60) |
133 | | -print(""" |
134 | | -Key Benefits: |
135 | | - • Track cache performance in production |
136 | | - • Identify optimization opportunities |
137 | | - • Set up alerts for low hit rates |
138 | | - • Monitor cache effectiveness over time |
139 | | - • Integrate with existing monitoring infrastructure |
140 | | -""") |
141 | | - |
142 | | -# Clean up |
143 | | -calculate_square.clear_cache() |
144 | | -calculate_cube.clear_cache() |
| 20 | + - targets: ['localhost:9090'] |
| 21 | +
|
| 22 | +3. Access metrics at http://localhost:9090/metrics |
| 23 | +
|
| 24 | +4. Create dashboards in Grafana or set up alerts based on: |
| 25 | + - cachier_cache_hit_rate (target: > 80%) |
| 26 | + - cachier_cache_misses_total (alert on spikes) |
| 27 | + - cachier_avg_latency_ms (monitor performance) |
| 28 | +
|
| 29 | +Available Metrics |
| 30 | +----------------- |
| 31 | +- cachier_cache_hits_total: Total number of cache hits |
| 32 | +- cachier_cache_misses_total: Total number of cache misses |
| 33 | +- cachier_cache_hit_rate: Cache hit rate percentage |
| 34 | +- cachier_avg_latency_ms: Average cache operation latency |
| 35 | +- cachier_stale_hits_total: Total stale cache hits |
| 36 | +- cachier_recalculations_total: Total cache recalculations |
| 37 | +- cachier_entry_count: Current number of cache entries |
| 38 | +- cachier_cache_size_bytes: Total cache size in bytes |
| 39 | +- cachier_size_limit_rejections_total: Entries rejected due to size limit |
| 40 | +
|
| 41 | +""" |
| 42 | + |
| 43 | +import time |
| 44 | + |
| 45 | +from cachier import cachier |
| 46 | +from cachier.exporters import PrometheusExporter |
| 47 | + |
| 48 | + |
| 49 | +def demo_basic_metrics(): |
| 50 | + """Demonstrate basic metrics collection.""" |
| 51 | + print("\n=== Basic Metrics Collection ===") |
| 52 | + |
| 53 | + @cachier(backend="memory", enable_metrics=True) |
| 54 | + def compute(x): |
| 55 | + time.sleep(0.1) # Simulate work |
| 56 | + return x * 2 |
| 57 | + |
| 58 | + compute.clear_cache() |
| 59 | + |
| 60 | + # Generate some traffic |
| 61 | + for i in range(5): |
| 62 | + result = compute(i) |
| 63 | + print(f" compute({i}) = {result}") |
| 64 | + |
| 65 | + # Access hits create cache hits |
| 66 | + for i in range(3): |
| 67 | + compute(i) |
| 68 | + |
| 69 | + stats = compute.metrics.get_stats() |
| 70 | + print("\nMetrics:") |
| 71 | + print(f" Hits: {stats.hits}") |
| 72 | + print(f" Misses: {stats.misses}") |
| 73 | + print(f" Hit Rate: {stats.hit_rate:.1f}%") |
| 74 | + print(f" Avg Latency: {stats.avg_latency_ms:.2f}ms") |
| 75 | + |
| 76 | + compute.clear_cache() |
| 77 | + |
| 78 | + |
| 79 | +def demo_prometheus_export(): |
| 80 | + """Demonstrate exporting metrics to Prometheus.""" |
| 81 | + print("\n=== Prometheus Export ===") |
| 82 | + |
| 83 | + @cachier(backend="memory", enable_metrics=True) |
| 84 | + def calculate(x, y): |
| 85 | + return x + y |
| 86 | + |
| 87 | + calculate.clear_cache() |
| 88 | + |
| 89 | + # Create exporter |
| 90 | + exporter = PrometheusExporter(port=9090, use_prometheus_client=False) |
| 91 | + exporter.register_function(calculate) |
| 92 | + |
| 93 | + # Generate some metrics |
| 94 | + calculate(1, 2) |
| 95 | + calculate(1, 2) # hit |
| 96 | + calculate(3, 4) # miss |
| 97 | + |
| 98 | + # Show text format metrics |
| 99 | + metrics_text = exporter._generate_text_metrics() |
| 100 | + print("\nGenerated Prometheus metrics:") |
| 101 | + print(metrics_text[:500] + "...") |
| 102 | + |
| 103 | + print("\nNote: In production, call exporter.start() to serve metrics") |
| 104 | + print(" Metrics would be available at http://localhost:9090/metrics") |
| 105 | + |
| 106 | + calculate.clear_cache() |
| 107 | + |
| 108 | + |
| 109 | +def main(): |
| 110 | + """Run all demonstrations.""" |
| 111 | + print("Cachier Prometheus Exporter Demo") |
| 112 | + print("=" * 60) |
| 113 | + |
| 114 | + # Print usage instructions from module docstring |
| 115 | + if __doc__: |
| 116 | + print(__doc__) |
| 117 | + |
| 118 | + demo_basic_metrics() |
| 119 | + demo_prometheus_export() |
| 120 | + |
| 121 | + print("\n" + "=" * 60) |
| 122 | + print("✓ All demonstrations completed!") |
| 123 | + |
| 124 | + |
| 125 | +if __name__ == "__main__": |
| 126 | + main() |
0 commit comments