Application Performance Monitoring (APM) agent for Node.js applications with transaction tracing, error tracking, custom metrics, and distributed tracing capabilities.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Configure automatic transaction naming patterns and URL filtering for better metric organization.
Add URL pattern-based naming rules with optional capture groups.
/**
* Add URL pattern-based transaction naming rule
* @param {RegExp|string} pattern - URL pattern to match (with optional capture groups)
* @param {string} name - Replacement name (can use $1, $2, etc. for capture groups)
*/
function addNamingRule(pattern, name);Ignore transactions matching specific URL patterns.
/**
* Ignore transactions matching URL pattern (useful for health checks, socket.io)
* @param {RegExp|string} pattern - URL pattern to ignore
*/
function addIgnoringRule(pattern);Both functions accept either string patterns or RegExp objects:
// String patterns (converted to RegExp)
newrelic.addNamingRule('^/api/v[0-9]+/users', 'API/Users');
// RegExp objects
newrelic.addNamingRule(/^\/api\/v[0-9]+\/users/, 'API/Users');
// Case-insensitive matching
newrelic.addNamingRule(/^\/API\/Users/i, 'API/Users');const newrelic = require('newrelic');
// Group user endpoints by ID pattern
newrelic.addNamingRule('^/users/[0-9]+$', 'Users/Show');
newrelic.addNamingRule('^/users/[0-9]+/edit$', 'Users/Edit');
newrelic.addNamingRule('^/users/[0-9]+/delete$', 'Users/Delete');
// Group API endpoints by version and resource
newrelic.addNamingRule('^/api/v[0-9]+/users', 'API/Users');
newrelic.addNamingRule('^/api/v[0-9]+/orders', 'API/Orders');
newrelic.addNamingRule('^/api/v[0-9]+/products', 'API/Products');// Capture API version and resource type
newrelic.addNamingRule('^/api/(v[1-5])/(users|orders|products|categories)', 'API/$1/$2');
// Matches: /api/v2/users → API/v2/users
// Matches: /api/v1/orders → API/v1/orders
// Capture nested resource patterns
newrelic.addNamingRule('^/(users|customers)/[0-9]+/(orders|invoices)', '$1/$2');
// Matches: /users/123/orders → users/orders
// Matches: /customers/456/invoices → customers/invoices
// Multi-level API grouping
newrelic.addNamingRule('^/api/(v[1-9])/([a-z]+)/(create|update|delete|show)$', 'API/$1/$2/$3');
// Matches: /api/v2/users/create → API/v2/users/create
// Matches: /api/v1/products/update → API/v1/products/update
// Admin vs regular endpoints
newrelic.addNamingRule('^/(admin|api)/([a-z]+)', '$1/$2');
// Matches: /admin/users → admin/users
// Matches: /api/orders → api/orders// Remove query parameters for cleaner grouping
newrelic.addNamingRule('^/search([?].*)?$', 'Search');
newrelic.addNamingRule('^/reports([?].*)?$', 'Reports');
// Group by main query parameter
newrelic.addNamingRule('^/search[?]type=([a-z]+)', 'Search/$1');
// Matches: /search?type=products → Search/products
// Matches: /search?type=users&limit=10 → Search/users// Health checks and monitoring
newrelic.addIgnoringRule('^/health$');
newrelic.addIgnoringRule('^/status$');
newrelic.addIgnoringRule('^/ping$');
newrelic.addIgnoringRule('^/metrics$');
newrelic.addIgnoringRule('^/ready$');
newrelic.addIgnoringRule('^/alive$');
// Static assets (if not handled by web server)
newrelic.addIgnoringRule('^/assets/');
newrelic.addIgnoringRule('^/static/');
newrelic.addIgnoringRule('^/public/');
newrelic.addIgnoringRule('\\.(css|js|png|jpg|gif|ico|woff|woff2)$');
// WebSocket and long-polling endpoints
newrelic.addIgnoringRule('^/socket\\.io/');
newrelic.addIgnoringRule('^/sockjs/');
newrelic.addIgnoringRule('^/ws/');
newrelic.addIgnoringRule('^/poll/');
// Development and debugging endpoints
newrelic.addIgnoringRule('^/debug/');
newrelic.addIgnoringRule('^/test/');
newrelic.addIgnoringRule('^/__webpack');// Express parameter routes
newrelic.addNamingRule('^/users/([0-9a-f-]{36})$', 'Users/Show'); // UUID
newrelic.addNamingRule('^/posts/([0-9]+)/comments$', 'Posts/Comments');
newrelic.addNamingRule('^/categories/([^/]+)/products$', 'Categories/Products');
// Express nested routes
newrelic.addNamingRule('^/api/v[0-9]+/users/[0-9]+/profile$', 'API/Users/Profile');
newrelic.addNamingRule('^/admin/([^/]+)/([^/]+)$', 'Admin/$1/$2');// RESTful resource patterns
newrelic.addNamingRule('^/api/([^/]+)$', 'API/$1/Index'); // GET /api/users
newrelic.addNamingRule('^/api/([^/]+)/[^/]+$', 'API/$1/Show'); // GET /api/users/123
newrelic.addNamingRule('^/api/([^/]+)/[^/]+/([^/]+)$', 'API/$1/$2'); // GET /api/users/123/posts
// HTTP method-based grouping (when using generic handlers)
newrelic.addNamingRule('^/api/([^/]+)/[0-9]+$', function(pattern, url) {
const resource = url.match(/^\/api\/([^\/]+)/)[1];
// This would need to be combined with method detection in practice
return `API/${resource}/Item`;
});// Group all GraphQL requests
newrelic.addNamingRule('^/graphql$', 'GraphQL/Query');
newrelic.addNamingRule('^/api/graphql$', 'GraphQL/Query');
// Subscription endpoints
newrelic.addIgnoringRule('^/graphql/subscriptions');// ✅ Good - Groups similar operations
newrelic.addNamingRule('^/users/[0-9]+$', 'Users/Show');
newrelic.addNamingRule('^/users/[0-9]+/edit$', 'Users/Edit');
newrelic.addNamingRule('^/products/[0-9]+$', 'Products/Show');
// ✅ Good - Uses capture groups for categorization
newrelic.addNamingRule('^/api/(v[1-3])/(users|orders)', 'API/$1/$2');// ❌ Bad - Creates too many unique metrics
newrelic.addNamingRule('^/users/([0-9]+)$', 'Users/$1'); // Each user ID = new metric
newrelic.addNamingRule('^/sessions/([a-f0-9-]+)$', 'Sessions/$1'); // Each session = new metric
// ❌ Bad - Includes timestamps or UUIDs
newrelic.addNamingRule('^/reports/([0-9]{8})$', 'Reports/$1'); // Date-based
newrelic.addNamingRule('^/files/([a-f0-9-]{36})$', 'Files/$1'); // UUID-based// ✅ Good - Ignores monitoring and health checks
newrelic.addIgnoringRule('^/health');
newrelic.addIgnoringRule('^/metrics');
newrelic.addIgnoringRule('^/favicon.ico$');
// ✅ Good - Ignores development endpoints
if (process.env.NODE_ENV !== 'production') {
newrelic.addIgnoringRule('^/debug/');
newrelic.addIgnoringRule('^/__webpack');
}// ✅ Good - Specific patterns are more efficient
newrelic.addNamingRule('^/api/v[1-3]/users$', 'API/Users/List');
// ❌ Less efficient - Overly broad patterns
newrelic.addNamingRule('.*users.*', 'Users'); // Matches too muchRules are applied in the order they are added. The first matching rule wins:
// Order matters!
newrelic.addNamingRule('^/api/v1/admin/users$', 'API/Admin/Users'); // More specific first
newrelic.addNamingRule('^/api/v1/users$', 'API/Users'); // Less specific second
// If reversed, admin users would match the generic pattern// You can test your patterns before deploying
function testNamingRule(pattern, testUrls) {
const regex = new RegExp(pattern);
testUrls.forEach(url => {
const match = url.match(regex);
console.log(`${url}: ${match ? 'matches' : 'no match'}`, match?.slice(1));
});
}
testNamingRule('^/api/(v[1-3])/(users|orders)', [
'/api/v1/users', // matches: ['v1', 'users']
'/api/v2/orders', // matches: ['v2', 'orders']
'/api/v1/products', // no match
'/api/v4/users' // no match
]);// Product catalog
newrelic.addNamingRule('^/products/[^/]+$', 'Products/Show');
newrelic.addNamingRule('^/categories/[^/]+$', 'Categories/Show');
newrelic.addNamingRule('^/search', 'Search');
// Shopping cart and checkout
newrelic.addNamingRule('^/cart$', 'Cart/Show');
newrelic.addNamingRule('^/checkout/([^/]+)$', 'Checkout/$1');
// User account
newrelic.addNamingRule('^/account/([^/]+)$', 'Account/$1');
newrelic.addNamingRule('^/orders/[0-9]+$', 'Orders/Show');// Dashboard and admin
newrelic.addNamingRule('^/dashboard$', 'Dashboard');
newrelic.addNamingRule('^/admin/([^/]+)$', 'Admin/$1');
// Settings and configuration
newrelic.addNamingRule('^/settings/([^/]+)$', 'Settings/$1');
newrelic.addNamingRule('^/config/([^/]+)$', 'Config/$1');
// Reports and analytics
newrelic.addNamingRule('^/reports/([^/]+)$', 'Reports/$1');
newrelic.addNamingRule('^/analytics', 'Analytics');// Versioned API endpoints
newrelic.addNamingRule('^/api/(v[1-9])/(auth|token)$', 'API/$1/Auth');
newrelic.addNamingRule('^/api/(v[1-9])/([^/]+)$', 'API/$1/$2');
newrelic.addNamingRule('^/api/(v[1-9])/([^/]+)/[^/]+$', 'API/$1/$2/Item');
// Webhooks
newrelic.addNamingRule('^/webhooks/([^/]+)$', 'Webhooks/$1');
// File uploads
newrelic.addNamingRule('^/upload', 'Upload');
newrelic.addNamingRule('^/files/upload$', 'Files/Upload');// Enable logging to see rule application
process.env.NEW_RELIC_LOG_LEVEL = 'debug';
// Test patterns in isolation
const testPattern = /^\/api\/(v[1-3])\/([^\/]+)/;
console.log('/api/v2/users'.match(testPattern)); // ['v2', 'users']You can also define naming rules in your newrelic.js configuration file:
// newrelic.js
exports.config = {
rules: {
name: [
{ pattern: '^/api/(v[1-3])/(users|orders)', name: 'API/$1/$2' },
{ pattern: '^/users/[0-9]+$', name: 'Users/Show' }
],
ignore: [
'^/health$',
'^/status$',
'^/socket\\.io/'
]
}
// ... other config
};