|
| 1 | +--- |
| 2 | +title: Span Metrics |
| 3 | +description: "Learn how to add custom metrics to your spans for enhanced performance monitoring and debugging." |
| 4 | +sidebar_order: 30 |
| 5 | +--- |
| 6 | + |
| 7 | +<Alert> |
| 8 | + |
| 9 | +To use span metrics effectively, you must first <PlatformLink to="/tracing/">set up tracing</PlatformLink> in your application. |
| 10 | + |
| 11 | +</Alert> |
| 12 | + |
| 13 | +Span metrics allow you to track custom performance data and debugging information within your application's traces. There are two main approaches to instrumenting metrics: |
| 14 | + |
| 15 | +1. Adding metrics to existing spans |
| 16 | +2. Creating dedicated spans with custom metrics |
| 17 | + |
| 18 | +## Adding Metrics to Existing Spans |
| 19 | + |
| 20 | +You can enhance existing spans with custom metrics by adding attributes. This is useful when you want to augment automatic instrumentation or add contextual data to spans you've already created. |
| 21 | + |
| 22 | +```javascript |
| 23 | +const span = Sentry.getActiveSpan(); |
| 24 | +if (span) { |
| 25 | + // Add individual metrics |
| 26 | + span.setAttribute('database.rows_affected', 42); |
| 27 | + span.setAttribute('cache.hit_rate', 0.85); |
| 28 | + |
| 29 | + // Add multiple metrics at once |
| 30 | + span.setAttributes({ |
| 31 | + 'memory.heap_used': 1024000, |
| 32 | + 'queue.length': 15, |
| 33 | + 'processing.duration_ms': 127 |
| 34 | + }); |
| 35 | +} |
| 36 | +``` |
| 37 | + |
| 38 | +### Best Practices for Span Attributes |
| 39 | + |
| 40 | +When adding metrics as span attributes: |
| 41 | + |
| 42 | +- Use consistent naming conventions (e.g., `category.metric_name`) |
| 43 | +- Keep attribute names concise but descriptive |
| 44 | +- Use appropriate data types (string, number, boolean, or arrays of these types) |
| 45 | +- Consider the cardinality of your metrics to avoid excessive unique combinations |
| 46 | + |
| 47 | +## Creating Dedicated Metric Spans |
| 48 | + |
| 49 | +For more detailed metric tracking, you can create dedicated spans that focus on specific metrics. This approach provides better organization and more precise timing data. |
| 50 | + |
| 51 | +```javascript |
| 52 | +Sentry.startSpan( |
| 53 | + { |
| 54 | + name: 'Database Query Metrics', |
| 55 | + op: 'db.metrics', |
| 56 | + attributes: { |
| 57 | + 'db.query_type': 'SELECT', |
| 58 | + 'db.table': 'users', |
| 59 | + 'db.execution_time_ms': 45, |
| 60 | + 'db.rows_returned': 100, |
| 61 | + 'db.connection_pool_size': 5 |
| 62 | + } |
| 63 | + }, |
| 64 | + () => { |
| 65 | + // Your database operation here |
| 66 | + } |
| 67 | +); |
| 68 | +``` |
| 69 | + |
| 70 | +### Common Metric Span Patterns |
| 71 | + |
| 72 | +Here are some common patterns for creating metric-focused spans: |
| 73 | + |
| 74 | +#### Performance Monitoring |
| 75 | +```javascript |
| 76 | +Sentry.startSpan( |
| 77 | + { |
| 78 | + name: 'Resource Usage Metrics', |
| 79 | + op: 'system.metrics', |
| 80 | + attributes: { |
| 81 | + 'cpu.usage_percent': 75.5, |
| 82 | + 'memory.used_mb': 1024, |
| 83 | + 'memory.free_mb': 512, |
| 84 | + 'disk.iops': 150 |
| 85 | + } |
| 86 | + }, |
| 87 | + async () => { |
| 88 | + // System operation being monitored |
| 89 | + } |
| 90 | +); |
| 91 | +``` |
| 92 | + |
| 93 | +#### Application Metrics |
| 94 | +```javascript |
| 95 | +Sentry.startSpan( |
| 96 | + { |
| 97 | + name: 'User Session Metrics', |
| 98 | + op: 'app.metrics', |
| 99 | + attributes: { |
| 100 | + 'session.duration_sec': 300, |
| 101 | + 'session.interactions': 25, |
| 102 | + 'session.errors': 0, |
| 103 | + 'session.latency_ms': 150 |
| 104 | + } |
| 105 | + }, |
| 106 | + () => { |
| 107 | + // Session-related code |
| 108 | + } |
| 109 | +); |
| 110 | +``` |
| 111 | + |
| 112 | +## Adding Metrics to All Spans |
| 113 | + |
| 114 | +To consistently add metrics across all spans in your application, you can use the `beforeSendTransaction` callback: |
| 115 | + |
| 116 | +```javascript |
| 117 | +Sentry.init({ |
| 118 | + beforeSendTransaction(event) { |
| 119 | + // Add metrics to the root span |
| 120 | + event.contexts.trace.data = { |
| 121 | + ...event.contexts.trace.data, |
| 122 | + 'app.version': '1.2.3', |
| 123 | + 'environment.region': 'us-west-2' |
| 124 | + }; |
| 125 | + |
| 126 | + // Add metrics to all child spans |
| 127 | + event.spans.forEach(span => { |
| 128 | + span.data = { |
| 129 | + ...span.data, |
| 130 | + 'app.component_version': '2.0.0', |
| 131 | + 'app.deployment_stage': 'production' |
| 132 | + }; |
| 133 | + }); |
| 134 | + |
| 135 | + return event; |
| 136 | + } |
| 137 | +}); |
| 138 | +``` |
| 139 | + |
| 140 | +## Best Practices for Span Metrics |
| 141 | + |
| 142 | +1. **Metric Naming** |
| 143 | + - Use clear, consistent naming patterns |
| 144 | + - Include the metric category (e.g., `db`, `cache`, `http`) |
| 145 | + - Use snake_case for metric names |
| 146 | + - Avoid high-cardinality values in metric names |
| 147 | + |
| 148 | +2. **Data Types** |
| 149 | + - Use appropriate numeric types for measurements |
| 150 | + - Use booleans for status flags |
| 151 | + - Use strings for categorical data |
| 152 | + - Use arrays when grouping related values |
| 153 | + |
| 154 | +3. **Performance Considerations** |
| 155 | + - Avoid adding too many metrics to a single span |
| 156 | + - Consider the overhead of metric collection |
| 157 | + - Use sampling when collecting high-frequency metrics |
| 158 | + - Balance metric granularity with system performance |
| 159 | + |
| 160 | +4. **Debugging and Monitoring** |
| 161 | + - Include relevant error and status information |
| 162 | + - Add timestamps for important events |
| 163 | + - Include correlation IDs for related operations |
| 164 | + - Add context that helps with troubleshooting |
| 165 | + |
| 166 | +## Common Use Cases |
| 167 | + |
| 168 | +### File Processing Operations |
| 169 | +```javascript |
| 170 | +Sentry.startSpan( |
| 171 | + { |
| 172 | + name: 'File Upload and Processing', |
| 173 | + op: 'file.process', |
| 174 | + attributes: { |
| 175 | + 'file.size_bytes': 15728640, // 15MB |
| 176 | + 'file.type': 'image/jpeg', |
| 177 | + 'file.name': 'user-profile.jpg', |
| 178 | + 'processing.steps_completed': ['resize', 'compress', 'metadata'], |
| 179 | + 'processing.output_size_bytes': 524288, // 512KB |
| 180 | + 'processing.compression_ratio': 0.033, |
| 181 | + 'upload.chunk_size': 1048576, // 1MB |
| 182 | + 'upload.chunks_completed': 15, |
| 183 | + 'upload.storage_provider': 's3', |
| 184 | + 'upload.cdn_propagation_ms': 1500, |
| 185 | + 'error.count': 0 |
| 186 | + } |
| 187 | + }, |
| 188 | + async () => { |
| 189 | + // File processing and upload execution |
| 190 | + } |
| 191 | +); |
| 192 | +``` |
| 193 | + |
| 194 | +### API Request Tracking |
| 195 | +```javascript |
| 196 | +Sentry.startSpan( |
| 197 | + { |
| 198 | + name: 'External API Call', |
| 199 | + op: 'http.client', |
| 200 | + attributes: { |
| 201 | + 'http.endpoint': '/api/users', |
| 202 | + 'http.response_size_bytes': 2048, |
| 203 | + 'http.retry_count': 0, |
| 204 | + 'http.cache_status': 'miss', |
| 205 | + 'http.response_time_ms': 200 |
| 206 | + } |
| 207 | + }, |
| 208 | + async () => { |
| 209 | + // API call execution |
| 210 | + } |
| 211 | +); |
| 212 | +``` |
| 213 | + |
| 214 | +### LLM API Integration |
| 215 | +```javascript |
| 216 | +Sentry.startSpan( |
| 217 | + { |
| 218 | + name: 'LLM Generation', |
| 219 | + op: 'ai.completion', |
| 220 | + attributes: { |
| 221 | + 'llm.model': 'gpt-4', |
| 222 | + 'llm.prompt_tokens': 425, |
| 223 | + 'llm.completion_tokens': 632, |
| 224 | + 'llm.total_tokens': 1057, |
| 225 | + 'llm.time_to_first_token_ms': 245, |
| 226 | + 'llm.total_duration_ms': 3250, |
| 227 | + 'llm.temperature': 0.7, |
| 228 | + 'llm.max_tokens': 2000, |
| 229 | + 'llm.stream_mode': true, |
| 230 | + 'llm.request_status': 'success' |
| 231 | + } |
| 232 | + }, |
| 233 | + async () => { |
| 234 | + // LLM API call execution |
| 235 | + } |
| 236 | +); |
| 237 | +``` |
| 238 | + |
| 239 | +### E-commerce Transaction |
| 240 | +```javascript |
| 241 | +Sentry.startSpan( |
| 242 | + { |
| 243 | + name: 'Purchase Transaction', |
| 244 | + op: 'commerce.checkout', |
| 245 | + attributes: { |
| 246 | + 'cart.item_count': 3, |
| 247 | + 'cart.total_amount': 159.99, |
| 248 | + 'cart.currency': 'USD', |
| 249 | + 'cart.items': ['SKU123', 'SKU456', 'SKU789'], |
| 250 | + 'payment.provider': 'stripe', |
| 251 | + 'payment.method': 'credit_card', |
| 252 | + 'payment.status': 'success', |
| 253 | + 'transaction.id': 'ord_123456789', |
| 254 | + 'customer.type': 'returning', |
| 255 | + 'shipping.method': 'express', |
| 256 | + 'promotion.code_applied': 'SUMMER23', |
| 257 | + 'promotion.discount_amount': 20.00 |
| 258 | + } |
| 259 | + }, |
| 260 | + async () => { |
| 261 | + // Checkout process execution |
| 262 | + } |
| 263 | +); |
| 264 | +``` |
0 commit comments