Setup Sentry Metrics in any project. Use this when asked to add Sentry metrics, track custom metrics, setup counters/gauges/distributions, or instrument application performance metrics. Supports JavaScript, TypeScript, Python, React, Next.js, and Node.js.
Sets up Sentry custom metrics (counters, gauges, distributions) in JavaScript/TypeScript and Python projects. Use this when asked to add Sentry metrics, track KPIs, or instrument performance monitoring.
/plugin marketplace add troykelly/claude-skills/plugin install issue-driven-development@troykelly-skillsThis skill is limited to using the following tools:
This skill helps configure Sentry's custom metrics feature to track counters, gauges, and distributions across your applications.
Invoke this skill when:
Sentry.metrics or sentry_sdk.metricsSupported Platforms:
Note: Ruby does not currently have dedicated metrics support in the Sentry SDK.
Before setup, explain the three metric types to the user:
| Type | Purpose | Use Cases | Aggregations |
|---|---|---|---|
| Counter | Track cumulative occurrences | Button clicks, API calls, errors | sum, per_second, per_minute |
| Gauge | Point-in-time snapshots | Queue depth, memory usage, connections | min, max, avg |
| Distribution | Statistical analysis of values | Response times, cart amounts, query duration | p50, p75, p95, p99, avg, min, max |
Check for these files:
package.json - Read to identify framework and Sentry SDK version@sentry/nextjs, @sentry/react, @sentry/node, @sentry/browserCheck for:
requirements.txt, pyproject.toml, setup.py, or Pipfilesentry-sdk version 2.44.0+ (required for metrics)Ask the user:
I'll help you set up Sentry Metrics. First, let me check your project setup.
After detecting the platform:
1. **What metrics do you want to track?**
- Counters: Event counts (clicks, API calls, errors)
- Gauges: Point-in-time values (queue depth, memory)
- Distributions: Value analysis (response times, amounts)
2. **Do you need metric filtering?**
- Yes: Configure beforeSendMetric to filter/modify metrics
- No: Send all metrics as-is
10.25.0+grep -E '"@sentry/(nextjs|react|node|browser)"' package.json
If version is below 10.25.0, inform user to upgrade:
npm install @sentry/nextjs@latest # or appropriate package
Metrics are enabled by default in SDK 10.25.0+. No changes to Sentry.init() are required unless user wants to disable or filter.
Locate init files:
instrumentation-client.ts, sentry.server.config.ts, sentry.edge.config.tssrc/index.tsx, src/main.tsx, or dedicated sentry config fileOptional: Explicitly enable (not required):
import * as Sentry from "@sentry/nextjs"; // or @sentry/react, @sentry/node
Sentry.init({
dsn: "YOUR_DSN_HERE",
// Metrics enabled by default, but can be explicit
enableMetrics: true,
// ... other existing config
});
If user wants to filter metrics before sending:
Sentry.init({
dsn: "YOUR_DSN_HERE",
beforeSendMetric: (metric) => {
// Drop metrics with sensitive attributes
if (metric.attributes?.sensitive === true) {
return null;
}
// Remove specific attribute before sending
if (metric.attributes?.internal) {
delete metric.attributes.internal;
}
return metric;
},
});
If user explicitly wants to disable metrics:
Sentry.init({
dsn: "YOUR_DSN_HERE",
enableMetrics: false,
});
Provide these examples to the user based on their use case:
// Basic counter - increment by 1
Sentry.metrics.count("button_click", 1);
// Counter with attributes for filtering/grouping
Sentry.metrics.count("api_call", 1, {
attributes: {
endpoint: "/api/users",
method: "GET",
status_code: 200,
},
});
// Counter for errors
Sentry.metrics.count("checkout_error", 1, {
attributes: {
error_type: "payment_declined",
payment_provider: "stripe",
},
});
// Counter for business events
Sentry.metrics.count("email_sent", 1, {
attributes: {
template: "welcome",
recipient_type: "new_user",
},
});
// Basic gauge
Sentry.metrics.gauge("queue_depth", 42);
// Memory usage gauge
Sentry.metrics.gauge("memory_usage", process.memoryUsage().heapUsed, {
unit: "byte",
attributes: {
process: "main",
},
});
// Connection pool gauge
Sentry.metrics.gauge("db_connections", 15, {
attributes: {
pool: "primary",
max_connections: 100,
},
});
// Active users gauge
Sentry.metrics.gauge("active_users", currentUserCount, {
attributes: {
region: "us-east",
},
});
// Response time distribution
Sentry.metrics.distribution("response_time", 187.5, {
unit: "millisecond",
attributes: {
endpoint: "/api/products",
method: "GET",
},
});
// Cart value distribution
Sentry.metrics.distribution("cart_value", 149.99, {
unit: "usd",
attributes: {
customer_tier: "premium",
},
});
// Query duration distribution
Sentry.metrics.distribution("db_query_duration", 45.2, {
unit: "millisecond",
attributes: {
query_type: "select",
table: "users",
},
});
// File size distribution
Sentry.metrics.distribution("upload_size", 2048576, {
unit: "byte",
attributes: {
file_type: "image",
},
});
// Force pending metrics to send immediately
await Sentry.flush();
// Useful before process exit or after critical operations
process.on("beforeExit", async () => {
await Sentry.flush();
});
sentry-sdk version 2.44.0+pip show sentry-sdk | grep Version
If version is below 2.44.0:
pip install --upgrade sentry-sdk
Metrics are enabled by default in SDK 2.44.0+. No changes required unless filtering is needed.
Common init locations:
settings.pyapp.py or __init__.pymain.pyimport sentry_sdk
def before_send_metric(metric, hint):
# Drop metrics with specific attributes
if metric.get("attributes", {}).get("sensitive"):
return None
# Modify metric before sending
if metric.get("attributes", {}).get("internal"):
del metric["attributes"]["internal"]
return metric
sentry_sdk.init(
dsn="YOUR_DSN_HERE",
before_send_metric=before_send_metric,
)
import sentry_sdk
# Basic counter
sentry_sdk.metrics.count("button_click", 1)
# Counter with attributes
sentry_sdk.metrics.count(
"api_call",
1,
attributes={
"endpoint": "/api/users",
"method": "GET",
"status_code": 200,
}
)
# Counter for errors
sentry_sdk.metrics.count(
"checkout_error",
1,
attributes={
"error_type": "payment_declined",
"payment_provider": "stripe",
}
)
# Business event counter
sentry_sdk.metrics.count(
"email_sent",
5, # Can increment by more than 1
attributes={
"template": "newsletter",
"batch_id": "batch_123",
}
)
import sentry_sdk
import psutil
# Basic gauge
sentry_sdk.metrics.gauge("queue_depth", 42)
# Memory usage gauge
sentry_sdk.metrics.gauge(
"memory_usage",
psutil.virtual_memory().used,
unit="byte",
attributes={"host": "web-01"}
)
# Database connection gauge
sentry_sdk.metrics.gauge(
"db_connections",
connection_pool.size(),
attributes={
"pool": "primary",
"max": connection_pool.max_size,
}
)
# Cache hit rate gauge
sentry_sdk.metrics.gauge(
"cache_hit_rate",
0.85,
attributes={"cache": "redis"}
)
import sentry_sdk
import time
# Response time distribution
start = time.time()
# ... do work ...
duration_ms = (time.time() - start) * 1000
sentry_sdk.metrics.distribution(
"response_time",
duration_ms,
unit="millisecond",
attributes={
"endpoint": "/api/products",
"method": "GET",
}
)
# Order value distribution
sentry_sdk.metrics.distribution(
"order_value",
order.total,
unit="usd",
attributes={
"customer_tier": customer.tier,
"payment_method": order.payment_method,
}
)
# Query duration distribution
sentry_sdk.metrics.distribution(
"db_query_duration",
query_time_ms,
unit="millisecond",
attributes={
"query_type": "select",
"table": "orders",
}
)
Use these units for better readability in Sentry dashboard:
| Category | Units |
|---|---|
| Time | nanosecond, microsecond, millisecond, second, minute, hour, day, week |
| Size | bit, byte, kilobyte, megabyte, gigabyte, terabyte |
| Currency | usd, eur, gbp (or any ISO currency code) |
| Rate | ratio, percent |
| Other | none (default), or custom string |
# Good - descriptive, namespaced
api.request.duration
checkout.cart.value
user.signup.completed
# Avoid - vague, inconsistent
duration
value1
myMetric
async function withTiming(name, fn, attributes = {}) {
const start = performance.now();
try {
return await fn();
} finally {
const duration = performance.now() - start;
Sentry.metrics.distribution(name, duration, {
unit: "millisecond",
attributes,
});
}
}
// Usage
const result = await withTiming(
"api.external.duration",
() => fetch("https://api.example.com/data"),
{ service: "example-api" }
);
import functools
import time
import sentry_sdk
def track_duration(metric_name, **extra_attrs):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
try:
return func(*args, **kwargs)
finally:
duration_ms = (time.time() - start) * 1000
sentry_sdk.metrics.distribution(
metric_name,
duration_ms,
unit="millisecond",
attributes=extra_attrs,
)
return wrapper
return decorator
# Usage
@track_duration("db.query.duration", query_type="user_lookup")
def get_user_by_id(user_id):
return db.query(User).filter(User.id == user_id).first()
function metricsMiddleware(req, res, next) {
const start = performance.now();
res.on("finish", () => {
const duration = performance.now() - start;
Sentry.metrics.distribution("http.request.duration", duration, {
unit: "millisecond",
attributes: {
method: req.method,
route: req.route?.path || req.path,
status_code: res.statusCode,
},
});
Sentry.metrics.count("http.request.count", 1, {
attributes: {
method: req.method,
status_code: res.statusCode,
},
});
});
next();
}
app.use(metricsMiddleware);
import time
import sentry_sdk
class SentryMetricsMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
start = time.time()
response = self.get_response(request)
duration_ms = (time.time() - start) * 1000
sentry_sdk.metrics.distribution(
"http.request.duration",
duration_ms,
unit="millisecond",
attributes={
"method": request.method,
"path": request.path,
"status_code": response.status_code,
},
)
return response
# Add to MIDDLEWARE in settings.py
After setup, provide these verification instructions:
// Add this temporarily to test
Sentry.metrics.count("test_metric", 1, {
attributes: { test: true },
});
Sentry.metrics.gauge("test_gauge", 42);
Sentry.metrics.distribution("test_distribution", 100, {
unit: "millisecond",
});
// Force flush to send immediately
await Sentry.flush();
import sentry_sdk
sentry_sdk.metrics.count("test_metric", 1, attributes={"test": True})
sentry_sdk.metrics.gauge("test_gauge", 42)
sentry_sdk.metrics.distribution("test_distribution", 100, unit="millisecond")
Tell user to check their Sentry dashboard under Metrics section to verify metrics are arriving.
Solutions:
enableMetrics: false)await Sentry.flush() or check aggregation windowSolutions:
beforeSendMetric to filter unnecessary metricsSolutions:
Solutions:
Provide this checklist after setup:
## Sentry Metrics Setup Complete
### Configuration Applied:
- [ ] SDK version verified (JS: 10.25.0+, Python: 2.44.0+)
- [ ] Metrics enabled (default) or explicitly configured
- [ ] Metric filtering configured (if requested)
### Instrumentation Added:
- [ ] Counter metrics for events/actions
- [ ] Gauge metrics for point-in-time values
- [ ] Distribution metrics for timing/values
- [ ] Appropriate units specified
- [ ] Meaningful attributes added
### Next Steps:
1. Run your application
2. Trigger actions that emit metrics
3. Check Sentry dashboard > Metrics section
4. Create dashboards and alerts based on metrics
| Platform | SDK Version | API Namespace |
|---|---|---|
| JavaScript | 10.25.0+ | Sentry.metrics.* |
| Python | 2.44.0+ | sentry_sdk.metrics.* |
| Method | JavaScript | Python |
|---|---|---|
| Counter | Sentry.metrics.count(name, value, options) | sentry_sdk.metrics.count(name, value, **kwargs) |
| Gauge | Sentry.metrics.gauge(name, value, options) | sentry_sdk.metrics.gauge(name, value, **kwargs) |
| Distribution | Sentry.metrics.distribution(name, value, options) | sentry_sdk.metrics.distribution(name, value, **kwargs) |
| Option | JavaScript | Python |
|---|---|---|
| Unit | { unit: "millisecond" } | unit="millisecond" |
| Attributes | { attributes: { key: "value" } } | attributes={"key": "value"} |
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.