# Custom metrics

> Add custom OpenTelemetry metrics and send them to Rocketlog

Beyond auto-instrumentation, you can emit **custom metrics** from your application using the OpenTelemetry Metrics API. Rocketlog ingests them via OTLP and you can use them in dashboards, alerts, and SLOs.

The OpenTelemetry metrics API supports **Counter**, **UpDownCounter**, **Histogram**, and **Gauge** (observable). Below are copy-paste examples for Python and Node.js. For full details, see the [OpenTelemetry Metrics API](https://opentelemetry.io/docs/specs/otel/metrics/api/) and language-specific docs.

## Python

Install the SDK and OTLP exporter if you haven’t already:

```bash
pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp
```

Configure the MeterProvider and export to your Rocketlog endpoint (same as in [Python instrumentation](/instrumentation/python)):

```python
from opentelemetry import metrics
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter
from opentelemetry.sdk.resources import Resource

resource = Resource.create({"service.name": "my-service"})
exporter = OTLPMetricExporter(endpoint="https://{your-ingress-endpoint}.rocketgraph.app/v1/metrics")
reader = PeriodicExportingMetricReader(exporter, export_interval_millis=10000)
provider = MeterProvider(resource=resource, metric_readers=[reader])
metrics.set_meter_provider(provider)

meter = metrics.get_meter("my-app", "1.0.0")
```

### Counter (monotonically increasing)

```python
request_count = meter.create_counter(
    "http_requests_total",
    description="Total HTTP requests",
    unit="1",
)
request_count.add(1, {"method": "GET", "path": "/api/users"})
request_count.add(2, {"method": "POST", "path": "/api/orders"})
```

### Histogram (distributions, e.g. duration)

```python
request_duration = meter.create_histogram(
    "http_request_duration_seconds",
    description="HTTP request duration",
    unit="s",
)
request_duration.record(0.25, {"method": "GET", "path": "/api/users"})
request_duration.record(1.3, {"method": "POST", "path": "/api/orders"})
```

### Observable Gauge (current value, e.g. queue size)

```python
def get_queue_size(options):
    # Read current queue size from your app
    options.observe(42, {"queue": "tasks"})

meter.create_observable_gauge(
    "queue_size",
    callbacks=[get_queue_size],
    description="Current queue size",
    unit="1",
)
```

---

## Node.js

Install the API, SDK, and OTLP exporter:

```bash
npm install @opentelemetry/api @opentelemetry/sdk-metrics @opentelemetry/exporter-metrics-otlp-http
```

Configure the MeterProvider (endpoint same as in [Node.js instrumentation](/instrumentation/node)):

```javascript
const { metrics } = require('@opentelemetry/api');
const { MeterProvider, PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics');
const { OTLPMetricExporter } = require('@opentelemetry/exporter-metrics-otlp-http');
const { Resource } = require('@opentelemetry/resources');

const resource = new Resource({ 'service.name': 'my-service' });
const exporter = new OTLPMetricExporter({
  url: 'https://{your-ingress-endpoint}.rocketgraph.app/v1/metrics',
});
const reader = new PeriodicExportingMetricReader({ exporter, exportIntervalMillis: 10000 });
const provider = new MeterProvider({ resource, readers: [reader] });
metrics.setGlobalMeterProvider(provider);

const meter = metrics.getMeter('my-app', '1.0.0');
```

### Counter

```javascript
const requestCount = meter.createCounter(
  'http_requests_total',
  { description: 'Total HTTP requests', unit: '1' }
);
requestCount.add(1, { method: 'GET', path: '/api/users' });
requestCount.add(2, { method: 'POST', path: '/api/orders' });
```

### Histogram

```javascript
const requestDuration = meter.createHistogram(
  'http_request_duration_seconds',
  { description: 'HTTP request duration', unit: 's' }
);
requestDuration.record(0.25, { method: 'GET', path: '/api/users' });
requestDuration.record(1.3, { method: 'POST', path: '/api/orders' });
```

### Observable Gauge

```javascript
const queueSize = meter.createObservableGauge(
  'queue_size',
  { description: 'Current queue size', unit: '1' }
);
queueSize.addCallback((result) => {
  const size = getQueueSizeFromApp(); // your logic
  result.observe(size, { queue: 'tasks' });
});
```

---

## Sending to Rocketlog

Use the **same OTLP endpoint** as for traces and logs: `https://{your-ingress-endpoint}.rocketgraph.app`. The metrics exporter uses the `/v1/metrics` path when using the HTTP exporter. Ensure your app or collector is configured with the same endpoint and that Rocketlog is set as the OTLP destination for metrics.

Once custom metrics are flowing, you can use them in the Rocketlog UI for dashboards, [alerts](/alerts-slos), and SLOs. For more instrument types and semantics, see the official [OpenTelemetry metrics documentation](https://opentelemetry.io/docs/concepts/signals/metrics/).
