Strapi plugin logo for Prometheus

Prometheus

strapi-prometheus is a simple plugin that exposes a metrics url for prometheus to scrape.

📊 Strapi Prometheus Plugin

npm downloads npm version license GitHub stars

A powerful middleware plugin that adds comprehensive Prometheus metrics to your Strapi application using prom-client 📈. Monitor your API performance, track system resources, and gain valuable insights into your application's behavior with just a few lines of configuration! 🚀

✨ Features

  • 🚀 Real-time API Metrics - Track HTTP request duration, payload sizes, and response codes with intelligent route normalization
  • 📈 System Monitoring - Collect Node.js process metrics as recommended by Prometheus
  • 🔒 Secure by Default - Dedicated metrics server (port 9000) isolated from your main application
  • 🏷️ Custom Labels - Add custom labels to categorize and filter your metrics across environments 🌍
  • 📊 Database Lifecycle Tracking - Monitor Strapi lifecycle events (create, update, delete) duration ⚡
  • 🔌 Easy Integration - Simple configuration with sensible defaults - get started in minutes!
  • 🆔 Version Tracking - Monitor Strapi version information for deployment tracking
  • 🎯 Smart Path Normalization - Flexible normalization with regex patterns or custom functions to group similar routes for better metric cardinality 📊
  • 📦 TypeScript Support - Built with TypeScript for better developer experience

⚡ Installation

1. Install the package 📦

npm install strapi-prometheus
# or
yarn add strapi-prometheus
# or
pnpm add strapi-prometheus

2. Install peer dependencies 🔧

npm install prom-client
# or
yarn add prom-client
# or
pnpm add prom-client

3. Configure the plugin ⚙️

Create or update your config/plugins.js (or config/plugins.ts for TypeScript):

1// config/plugins.js
2module.exports = {
3  // ...other plugins
4  prometheus: {
5    enabled: true,
6    config: {
7      // Optional: Collect Node.js default metrics
8      // See collectDefaultMetricsOption of prom-client for all options
9      collectDefaultMetrics: false, // or { prefix: 'my_app_' }
10      
11      // Optional: Add custom labels to all metrics
12      labels: { 
13        app: "my-strapi-app",
14        environment: "production"
15      },
16      
17      // Server configuration
18      // Set to false to expose metrics on your main Strapi server (not recommended)
19      server: {
20        port: 9000,           // Metrics server port
21        host: '0.0.0.0',      // Metrics server host
22        path: '/metrics'      // Metrics endpoint path
23      },
24      // OR disable separate server (use with caution):
25      // server: false
26      
27      // 🎯 Path Normalization Rules
28      normalize: [
29        [/\/(?:[a-z0-9]{24,25}|\d+)(?=\/|$)/, '/:id'], // Document IDs or numeric IDs
30        [/\/uploads\/[^\/]+\.[a-zA-Z0-9]+/, '/uploads/:file'], // Uploaded files with extensions
31      ]
32    }
33  }
34};

For TypeScript projects:

1// config/plugins.ts
2export default {
3  prometheus: {
4    enabled: true,
5    config: {
6      collectDefaultMetrics: false,
7      labels: { 
8        app: "my-strapi-app",
9        environment: process.env.NODE_ENV || "development"
10      },
11      server: {
12        port: parseInt(process.env.METRICS_PORT || '9000'),
13        host: process.env.METRICS_HOST || '0.0.0.0',
14        path: '/metrics'
15      },
16      
17      // Custom normalization function (alternative to array rules)
18      normalize: (ctx) => {
19        let path = ctx.path;
20        
21        // Custom logic for your specific needs
22        if (path.startsWith('/api/')) {
23          path = path.replace(/\/\d+/g, '/:id'); // Replace numeric IDs
24        }
25        
26        return path;
27      }
28    }
29  }
30};

📊 Available Metrics

The plugin automatically collects the following metrics with intelligent route pattern detection ✨:

Metric NameDescriptionTypeLabels
http_request_duration_secondsDuration of HTTP requests in seconds ⏱️Histogramorigin, method, route, status
http_request_content_length_bytesSize of request payloads in bytes 📤Histogramorigin, method, route, status
http_response_content_length_bytesSize of response payloads in bytes 📥Histogramorigin, method, route, status
strapi_version_infoStrapi version information 🏷️Gaugeversion
lifecycle_duration_secondsDuration of Strapi database lifecycle events 💾Histogramevent

Optional System Metrics

When collectDefaultMetrics is enabled, you'll also get Node.js process metrics:

  • process_cpu_user_seconds_total - CPU time spent in user mode
  • process_cpu_system_seconds_total - CPU time spent in system mode
  • process_start_time_seconds - Process start time
  • process_resident_memory_bytes - Resident memory size
  • nodejs_heap_size_total_bytes - Total heap size
  • nodejs_heap_size_used_bytes - Used heap size
  • nodejs_external_memory_bytes - External memory usage
  • And more...

🎯 Smart Path Normalization

The plugin features intelligent path normalization to ensure optimal metric cardinality by grouping similar routes together ✨

📝 Configuration Options

You can configure path normalization in two ways:

1. Array of Regex Rules (Recommended)

Use an array of [RegExp, replacement] tuples to define normalization patterns:

1normalize: [
2  [/\/(?:[a-z0-9]{24,25}|\d+)(?=\/|$)/, '/:id'], // Document IDs or numeric IDs
3  [/\/uploads\/[^\/]+\.[a-zA-Z0-9]+/, '/uploads/:file'], // Uploaded files with extensions
4  
5  // Custom patterns
6  [/\/users\/\d+/, '/users/:id'],                                   // /users/123
7  [/\/orders\/ORD\d+/, '/orders/:orderCode']                        // /orders/ORD12345
8]

2. Custom Function

Use a function for dynamic normalization logic:

1normalize: (ctx) => {
2  let path = ctx.path;
3  
4  // Custom normalization logic
5  if (path.startsWith('/api/')) {
6    path = path.replace(/\/\d+/g, '/:id');           // Replace numeric IDs
7    path = path.replace(/\/[a-f0-9-]{36}/gi, '/:uuid'); // Replace UUIDs
8  }
9  
10  // Multi-tenant example
11  if (path.startsWith('/tenant/')) {
12    path = path.replace(/^\/tenant\/[^\/]+/, '/tenant/:id');
13  }
14  
15  return path;
16}

🏷️ Built-in Patterns

The plugin includes pre-configured patterns for common Strapi routes:

Original PathNormalized PathDescription
/api/posts/123/api/posts/:idAPI resource with ID
/api/posts/123/comments/456/api/posts/:id/comments/:idNested resources
/admin/content-manager/collection-types/api::post.post/123/admin/content-manager/:type/:contentType/:idAdmin content manager
/uploads/image.jpg/uploads/:fileFile uploads
/en/api/posts/123/:locale/api/posts/:idi18n localized routes
/fr-FR/dashboard/:locale/dashboardLocale-specific pages

🚀 Benefits

  • Low Cardinality - Groups similar routes to prevent metric explosion
  • Prometheus-Friendly - Follows Prometheus best practices
  • Flexible - Support both regex patterns and custom functions
  • Performance - Efficient pattern matching with minimal overhead
  • Strapi-Aware - Built-in knowledge of Strapi routing conventions

🚀 Quick Start

  1. 📦 Install and configure the plugin (see Installation)
  2. 🎬 Start your Strapi application
  3. 📊 Metrics will be available at http://localhost:9000/metrics
  4. 🔗 Configure Prometheus to scrape this endpoint

📊 Accessing Metrics

Dedicated Server (Default & Recommended)

By default, metrics are served on a separate server:

curl http://localhost:9000/metrics

Main Strapi Server (Not Recommended)

If you set server: false, metrics will be available on your main Strapi server:

# Requires authentication token
curl -H "Authorization: Bearer YOUR_API_TOKEN" http://localhost:1337/api/metrics

👮‍♀️ Security Considerations

!CAUTION Metrics can contain sensitive information about your application's usage patterns, performance characteristics, and potentially user behavior. Always secure your metrics endpoint appropriately.

Recommended: Dedicated Server (Default)

The plugin starts a separate server on port 9000 by default, isolated from your main application:

  • Secure by design - No external access to your main application
  • Simple firewall rules - Block port 9000 from external access
  • Performance - No impact on your main application
  • Monitoring-specific - Dedicated to metrics collection

Alternative: Main Server Integration

You can expose metrics on your main Strapi server by setting server: false:

  • ⚠️ Authentication required - Protected by Strapi's auth middleware
  • ⚠️ API token needed - Must create and manage API tokens
  • ⚠️ Potential exposure - Metrics endpoint on your main application
  • ⚠️ Performance impact - Additional load on main server

We strongly recommend using the dedicated server approach.

🤝 Compatibility

Strapi VersionPlugin VersionStatus
v5.xv2.x.x✅ Fully Supported ⭐
v4.xv1.x.x❌ EOL 🔧

Note: For new projects, we recommend using Strapi v5.x with the latest plugin version! 🎯

📊 Grafana Dashboards

Ready-to-use Grafana dashboards for visualizing your Strapi metrics:

Official Dashboards

Contributing Dashboards

Have a great dashboard? We'd love to feature it! Please open a pull request with your dashboard JSON. 🎨

🔍 Troubleshooting

Common Issues

Metrics server not starting

  • Check if port 9000 is already in use
  • Verify firewall settings
  • Check Strapi logs for error messages

No metrics appearing

  • Ensure the plugin is properly enabled in config/plugins.js
  • Verify that prom-client is installed
  • Check that requests are being made to your Strapi application

Memory usage increasing

  • Consider disabling collectDefaultMetrics if not needed
  • Review custom labels - avoid high-cardinality labels
  • Monitor Prometheus scrape interval

🆘 Getting Help

🏗️ v1 → v2 Migration Guide

🏗️ Migration Guide (v1 → v2)

Version 2.0 brings significant improvements and Strapi v5 support. Here's what you need to know:

🔧 Configuration Changes

Old (v1):

1module.exports = {
2  'strapi-prometheus': {
3    enabled: true,
4    config: {
5      // v1 config
6    }
7  }
8};

New (v2):

1module.exports = {
2  prometheus: {  // ← Plugin name simplified
3    enabled: true,
4    config: {
5      // v2 config (see configuration section above)
6    }
7  }
8};

🚀 New Features in v2

  • Dedicated metrics server - Default behavior for better security
  • Simplified configuration - Easier setup and maintenance
  • Strapi v5 support - Future-ready compatibility
  • Enhanced metrics - More comprehensive monitoring
  • Improved performance - Optimized for production use

📊 Metric and Label Changes

v1 Metricv2 MetricChange
http_request_duration_shttp_request_duration_seconds✅ Renamed for clarity
http_request_size_byteshttp_request_content_length_bytes✅ Renamed for accuracy
http_response_size_byteshttp_response_content_length_bytes✅ Renamed for accuracy
Labels: pathLabels: route✅ More consistent route patterns
Apollo metrics🗑️ Removed - use apollo-prometheus-exporter
-http_requests_total✅ New counter metric
-http_active_requests✅ New gauge metric

🏷️ Enhanced Label Strategy

v2 Improvements:

  • Smart route detection - Uses _matchedRoute when available for accurate patterns
  • Consistent normalization - /api/articles/123/api/articles/:id
  • Low cardinality - Prevents metric explosion from dynamic paths
  • Added origin label - Track requests by source

🔄 Migration Steps

  1. Update plugin name in your configuration
  2. Review new configuration options (especially server settings)
  3. Update Prometheus scrape config if using custom settings
  4. Update Grafana dashboards with new metric names
  5. Test thoroughly in development before production deployment

⚠️ Breaking Changes

  • Apollo metrics removed - If you were using Apollo GraphQL metrics, you'll need to implement them separately
  • Custom registry removed - Now uses the default prom-client registry (this actually gives you more flexibility!)
  • Configuration structure changed - Follow the new configuration format

💡 Recommendations

  • Start with default settings and customize as needed
  • Use the dedicated metrics server (default behavior)
  • Monitor your Prometheus targets after migration
  • Consider this a good time to review your monitoring setup

🤝 Contributing

We welcome contributions! Here's how you can help:

🐛 Reporting Issues

  • Use the issue tracker 📝
  • Search existing issues before creating new ones 🔍
  • Provide clear reproduction steps 📋
  • Include environment details (Strapi version, Node.js version, OS) 💻

💻 Development

  1. Fork the repository 🍴
  2. Create a feature branch: git checkout -b feature/amazing-feature 🌿
  3. Make your changes ✨
  4. Add tests if applicable 🧪
  5. Commit with clear messages: git commit -m 'Add amazing feature' 💬
  6. Push to your branch: git push origin feature/amazing-feature 🚀
  7. Open a Pull Request 🔄

📝 Documentation

  • Improve README documentation 📖
  • Add code examples 💡
  • Create tutorials or blog posts ✍️
  • Share Grafana dashboards 📊

📜 License

This project is licensed under the MIT License - see the LICENSE file for details.

👨‍💻 Author & Maintainer

Xander Denecker (@XanderD99)

🙏 Acknowledgments

  • Prometheus - The monitoring system that makes this all possible
  • prom-client - The Node.js Prometheus client library
  • Strapi - The leading open-source headless CMS
  • All contributors who have helped improve this plugin

⭐ If this plugin helps you, please consider giving it a star on GitHub!

Install now

npm install strapi-prometheus

STATS

18 GitHub stars1647 weekly downloads

Last updated

7 days ago

Strapi Version

5.0.0 and above

Author

github profile image for XanderD99
XanderD99

Useful links

Create your own plugin

Check out the available plugin resources that will help you to develop your plugin or provider and get it listed on the marketplace.