> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/open-telemetry/opentelemetry-rust/llms.txt
> Use this file to discover all available pages before exploring further.

# Counter

> Record monotonically increasing values with Counter instruments in OpenTelemetry Rust

A `Counter` is a synchronous instrument that records values that only increase over time. Counters are ideal for tracking totals like request counts, bytes sent, or errors encountered.

## When to Use Counter

Use a Counter when:

* Values only increase (never decrease)
* You're counting discrete events
* You want to track cumulative totals
* Resets should only happen on application restart

**Common examples:**

* HTTP requests served
* Bytes transmitted
* Errors encountered
* Items processed
* Cache hits

<Warning>
  Do not use Counter for values that can decrease. Use `UpDownCounter` instead.
</Warning>

## API Reference

```rust theme={null}
pub struct Counter<T>(Arc<dyn SyncInstrument<T> + Send + Sync>);

impl<T> Counter<T> {
    pub fn add(&self, value: T, attributes: &[KeyValue]);
}
```

The `add` method records an increment to the counter. The value must be non-negative.

## Creating a Counter

Counters support `u64` and `f64` data types:

```rust theme={null}
use opentelemetry::global;

let meter = global::meter("my-app");

// u64 counter
let u64_counter = meter.u64_counter("requests_total")
    .with_description("Total number of requests")
    .with_unit("requests")
    .build();

// f64 counter
let f64_counter = meter.f64_counter("bytes_sent")
    .with_description("Total bytes sent")
    .with_unit("By")
    .build();
```

## Recording Measurements

Use the `add` method to record increments:

```rust theme={null}
use opentelemetry::KeyValue;

// Record a simple increment
u64_counter.add(1, &[]);

// Record with attributes
u64_counter.add(
    1,
    &[
        KeyValue::new("method", "GET"),
        KeyValue::new("status", "200"),
        KeyValue::new("endpoint", "/api/users"),
    ],
);

// Record larger increments
f64_counter.add(1024.5, &[KeyValue::new("protocol", "http")]);
```

## Complete Example

Here's a complete example tracking HTTP requests:

```rust theme={null}
use opentelemetry::{global, KeyValue};
use opentelemetry_sdk::metrics::SdkMeterProvider;
use opentelemetry_sdk::Resource;

fn init_meter_provider() -> SdkMeterProvider {
    let exporter = opentelemetry_stdout::MetricExporterBuilder::default().build();
    let provider = SdkMeterProvider::builder()
        .with_periodic_exporter(exporter)
        .with_resource(
            Resource::builder()
                .with_service_name("my-service")
                .build(),
        )
        .build();
    global::set_meter_provider(provider.clone());
    provider
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let meter_provider = init_meter_provider();
    let meter = global::meter("http-server");

    // Create a counter for HTTP requests
    let request_counter = meter
        .u64_counter("http_requests_total")
        .with_description("Total number of HTTP requests")
        .with_unit("requests")
        .build();

    // Simulate handling requests
    request_counter.add(
        1,
        &[
            KeyValue::new("method", "GET"),
            KeyValue::new("endpoint", "/api/users"),
            KeyValue::new("status", "200"),
        ],
    );

    request_counter.add(
        1,
        &[
            KeyValue::new("method", "POST"),
            KeyValue::new("endpoint", "/api/users"),
            KeyValue::new("status", "201"),
        ],
    );

    meter_provider.shutdown()?;
    Ok(())
}
```

## Attributes and Cardinality

Attributes add dimensions to your counter, allowing you to slice the data in different ways:

```rust theme={null}
counter.add(1, &[
    KeyValue::new("method", "GET"),
    KeyValue::new("endpoint", "/api/users"),
    KeyValue::new("status", "200"),
]);

counter.add(1, &[
    KeyValue::new("method", "GET"),
    KeyValue::new("endpoint", "/api/posts"),
    KeyValue::new("status", "200"),
]);
```

Each unique combination of attributes creates a separate time series.

<Warning>
  **Cardinality matters!** Each unique attribute combination creates a new time series. Avoid high-cardinality attributes like user IDs or request IDs, as they can cause memory issues and poor query performance.
</Warning>

### Good Attributes (Low Cardinality)

* HTTP method (GET, POST, PUT, DELETE)
* HTTP status code (200, 404, 500)
* Endpoint patterns (/api/users, /api/posts)
* Environment (production, staging)
* Region (us-east-1, eu-west-1)

### Bad Attributes (High Cardinality)

* User IDs
* Request IDs
* Timestamps
* Email addresses
* Full URLs with query parameters

## Cloning Counters

Counters implement `Clone`, allowing you to share them across your application:

```rust theme={null}
let counter = meter.u64_counter("requests").build();
let counter_clone = counter.clone();

// Both reference the same underlying counter
counter.add(1, &[]);
counter_clone.add(1, &[]);
```

<Tip>
  Clone counters rather than creating duplicates with the same name. Creating multiple counters with the same name can lower SDK performance.
</Tip>

## Counter vs. ObservableCounter

Choose based on how you track the data:

<CodeGroup>
  ```rust Counter (Synchronous) theme={null}
  // Use when incrementing inline with your code
  let counter = meter.u64_counter("requests").build();

  fn handle_request() {
      // Increment as events happen
      counter.add(1, &[KeyValue::new("endpoint", "/api/users")]);
  }
  ```

  ```rust ObservableCounter (Asynchronous) theme={null}
  // Use when reading from an external source
  let _observable_counter = meter
      .u64_observable_counter("cpu_time")
      .with_callback(|observer| {
          // Read from system API
          let cpu_time = read_cpu_time();
          observer.observe(cpu_time, &[]);
      })
      .build();
  ```
</CodeGroup>

See [Observable Instruments](/metrics/observable-instruments) for more details on asynchronous counters.

## UpDownCounter Alternative

If your values can both increase and decrease, use `UpDownCounter` instead:

```rust theme={null}
let updown_counter = meter.i64_up_down_counter("active_connections")
    .with_description("Number of active connections")
    .build();

// Can add positive or negative values
updown_counter.add(1, &[]);  // Connection opened
updown_counter.add(-1, &[]); // Connection closed
```

## Best Practices

1. **Use descriptive names**: `http_requests_total` is better than `requests`
2. **Include units**: Specify units like `"requests"`, `"By"` (bytes), or `"ms"`
3. **Keep cardinality low**: Limit unique attribute combinations
4. **Reuse instruments**: Clone counters instead of creating duplicates
5. **Choose the right type**: Use `u64` for counts, `f64` for fractional values

## Next Steps

<CardGroup cols={2}>
  <Card title="Histogram" href="/metrics/histogram">
    Record value distributions like request latency
  </Card>

  <Card title="Gauge" href="/metrics/gauge">
    Record independent point-in-time values
  </Card>

  <Card title="Observable Instruments" href="/metrics/observable-instruments">
    Use callbacks to report measurements
  </Card>

  <Card title="Views" href="/metrics/views">
    Customize how counters are aggregated
  </Card>
</CardGroup>
