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

# Metrics

> Learn about k6's built-in metrics and how to create custom metrics to track test performance.

Metrics are the heart of k6 performance testing. k6 automatically collects built-in metrics and allows you to define custom metrics for your specific testing needs.

## Metric Types

k6 supports four metric types, defined in `metrics/metric_type.go`:

### Counter

A metric that sums all added values. From `metrics/metric_type.go`:

```javascript theme={null}
import { Counter } from 'k6/metrics';

const myCounter = new Counter('my_counter');

export default function() {
  myCounter.add(1);  // Increment by 1
  myCounter.add(5);  // Increment by 5
  // Total: 6
}
```

**Aggregation methods:** `count`, `rate`

### Gauge

A metric that stores the latest value. From `metrics/metric_type.go`:

```javascript theme={null}
import { Gauge } from 'k6/metrics';

const myGauge = new Gauge('my_gauge');

let maxResponseTime = 0.0;

export default function() {
  const res = http.get('https://quickpizza.grafana.com/');
  maxResponseTime = Math.max(maxResponseTime, res.timings.duration);
  myGauge.add(maxResponseTime);  // Store current max
}
```

**Aggregation methods:** `value`

### Trend

A metric that tracks all values and calculates statistics. From `metrics/metric_type.go`:

```javascript theme={null}
import { Trend } from 'k6/metrics';

const myTrend = new Trend('my_trend');

export default function() {
  const res = http.get('https://quickpizza.grafana.com/');
  // Track connection + TLS time
  myTrend.add(res.timings.connecting + res.timings.tls_handshaking);
}
```

**Aggregation methods:** `avg`, `min`, `max`, `med`, `p(N)` (percentiles)

### Rate

A metric that tracks the percentage of non-zero values. From `metrics/metric_type.go`:

```javascript theme={null}
import { Rate } from 'k6/metrics';
import { check } from 'k6';

const myRate = new Rate('my_rate');

export default function() {
  const res = http.get('https://quickpizza.grafana.com/');
  const passed = check(res, { 'status is 200': (r) => r.status === 200 });
  
  myRate.add(passed);  // Add true (1) or false (0)
  // Rate calculates: (number of trues) / (total samples)
}
```

**Aggregation methods:** `rate`

## Built-in Metrics

k6 automatically collects comprehensive metrics defined in `metrics/builtin.go`:

### HTTP Metrics

From `metrics/builtin.go`, HTTP-related metrics:

#### `http_reqs`

**Type:** Counter\
**Description:** Total number of HTTP requests

#### `http_req_failed`

**Type:** Rate\
**Description:** Rate of failed requests (status >= 400 or network error)

```javascript theme={null}
export const options = {
  thresholds: {
    http_req_failed: ['rate<0.01'], // Less than 1% failures
  },
};
```

#### `http_req_duration`

**Type:** Trend (Time)\
**Description:** Total request time (sending + waiting + receiving)

```javascript theme={null}
export const options = {
  thresholds: {
    http_req_duration: ['p(95)<500'], // 95% under 500ms
  },
};
```

#### `http_req_blocked`

**Type:** Trend (Time)\
**Description:** Time blocked before initiating request (waiting for free TCP connection)

#### `http_req_connecting`

**Type:** Trend (Time)\
**Description:** Time spent establishing TCP connection

#### `http_req_tls_handshaking`

**Type:** Trend (Time)\
**Description:** Time spent in TLS handshake

#### `http_req_sending`

**Type:** Trend (Time)\
**Description:** Time spent sending request data

#### `http_req_waiting`

**Type:** Trend (Time)\
**Description:** Time spent waiting for response (TTFB - Time To First Byte)

#### `http_req_receiving`

**Type:** Trend (Time)\
**Description:** Time spent receiving response data

### VU and Iteration Metrics

#### `vus`

**Type:** Gauge\
**Description:** Current number of active virtual users

#### `vus_max`

**Type:** Gauge\
**Description:** Maximum number of VUs initialized

#### `iterations`

**Type:** Counter\
**Description:** Total number of completed iterations

#### `iteration_duration`

**Type:** Trend (Time)\
**Description:** Time to complete one full iteration

#### `dropped_iterations`

**Type:** Counter\
**Description:** Iterations that couldn't start due to time constraints

### Check Metrics

#### `checks`

**Type:** Rate\
**Description:** Success rate of checks

```javascript theme={null}
import { check } from 'k6';

export const options = {
  thresholds: {
    checks: ['rate>0.95'], // 95% of checks must pass
  },
};

export default function() {
  const res = http.get('https://quickpizza.grafana.com/');
  check(res, {
    'status is 200': (r) => r.status === 200,
  });
}
```

### Group Metrics

#### `group_duration`

**Type:** Trend (Time)\
**Description:** Time spent inside a group

```javascript theme={null}
import { group } from 'k6';

export default function() {
  group('user flow', function() {
    http.get('https://quickpizza.grafana.com/');
    http.get('https://quickpizza.grafana.com/api/pizza');
  });
}
```

### WebSocket Metrics

From `metrics/builtin.go`, WebSocket-specific metrics:

* `ws_sessions` (Counter) - Total WebSocket sessions
* `ws_msgs_sent` (Counter) - Messages sent
* `ws_msgs_received` (Counter) - Messages received
* `ws_ping` (Trend, Time) - Ping duration
* `ws_session_duration` (Trend, Time) - Session duration
* `ws_connecting` (Trend, Time) - Connection time

### gRPC Metrics

#### `grpc_req_duration`

**Type:** Trend (Time)\
**Description:** gRPC request duration

### Network Metrics

#### `data_sent`

**Type:** Counter (Data)\
**Description:** Amount of data sent (bytes)

#### `data_received`

**Type:** Counter (Data)\
**Description:** Amount of data received (bytes)

## Custom Metrics

Create custom metrics to track application-specific data. From `examples/custom_metrics.js`:

```javascript theme={null}
import http from 'k6/http';
import { Counter, Gauge, Rate, Trend } from 'k6/metrics';
import { check } from 'k6';

// Define custom metrics in init context
const myCounter = new Counter('my_counter');
const myGauge = new Gauge('my_gauge');
const myRate = new Rate('my_rate');
const myTrend = new Trend('my_trend');

let maxResponseTime = 0.0;

export default function () {
  const res = http.get('https://quickpizza.grafana.com/');
  const passed = check(res, { 'status is 200': (r) => r.status === 200 });

  // Add one for number of requests
  myCounter.add(1);

  // Set max response time seen
  maxResponseTime = Math.max(maxResponseTime, res.timings.duration);
  myGauge.add(maxResponseTime);

  // Add check success or failure to keep track of rate
  myRate.add(passed);

  // Keep track of TCP-connecting and TLS handshaking part of response time
  myTrend.add(res.timings.connecting + res.timings.tls_handshaking);
}
```

## Metric Tags

From `metrics/tags.go`, metrics can be filtered using tags:

### System Tags

Automatic tags from `metrics/system_tag.go`:

* `method` - HTTP method
* `status` - HTTP status code
* `url` - Request URL
* `name` - Request name
* `group` - Group name
* `check` - Check name
* `scenario` - Scenario name
* `service` - Service name (for gRPC)

### Custom Tags

Add custom tags to requests:

```javascript theme={null}
import http from 'k6/http';

export default function() {
  // Tag individual requests
  http.get('https://quickpizza.grafana.com/api/pizza', {
    tags: { my_tag: 'pizza_api' },
  });
  
  // Filter metrics by tag in thresholds
}

export const options = {
  thresholds: {
    'http_req_duration{my_tag:pizza_api}': ['p(95)<200'],
  },
};
```

### Global Tags

Apply tags to all metrics:

```javascript theme={null}
export const options = {
  tags: {
    environment: 'production',
    team: 'backend',
  },
};
```

## Metric Output

### End-of-Test Summary

k6 displays metric statistics at test completion:

```
     ✓ status is 200

     checks.........................: 100.00% ✓ 150      ✗ 0   
     data_received..................: 4.5 MB  75 kB/s
     data_sent......................: 13 kB   217 B/s
     http_req_blocked...............: avg=1.5ms    min=1µs     med=5µs     max=145ms   p(95)=7µs   
     http_req_connecting............: avg=516µs    min=0s      med=0s      max=48ms    p(95)=0s    
     http_req_duration..............: avg=123ms    min=101ms   med=115ms   max=245ms   p(95)=187ms 
     http_req_failed................: 0.00%   ✓ 0        ✗ 150 
     http_req_receiving.............: avg=128µs    min=22µs    med=85µs    max=1.5ms   p(95)=294µs 
     http_req_sending...............: avg=34µs     min=7µs     med=24µs    max=208µs   p(95)=80µs  
     http_req_tls_handshaking.......: avg=0s       min=0s      med=0s      max=0s      p(95)=0s    
     http_req_waiting...............: avg=122ms    min=101ms   med=115ms   max=244ms   p(95)=186ms 
     http_reqs......................: 150     2.5/s
     iteration_duration.............: avg=1.12s    min=1.1s    med=1.11s   max=1.24s   p(95)=1.18s 
     iterations.....................: 150     2.5/s
     vus............................: 3       min=3      max=3 
     vus_max........................: 3       min=3      max=3
```

## Metric Value Types

From `metrics/value_type.go`, metrics can represent:

* **Default** - Generic numeric values
* **Time** - Duration values (milliseconds)
* **Data** - Data size values (bytes)

```javascript theme={null}
import { Trend } from 'k6/metrics';

// Time metric
const responseTime = new Trend('response_time', true);

// Default metric
const itemCount = new Trend('item_count');
```

## Advanced Metric Patterns

### Tracking Business Metrics

```javascript theme={null}
import { Counter, Trend } from 'k6/metrics';

const ordersCreated = new Counter('orders_created');
const orderValue = new Trend('order_value');

export default function() {
  const res = http.post('https://api.example.com/orders', JSON.stringify({
    items: ['pizza', 'soda'],
    total: 25.50,
  }));
  
  if (res.status === 201) {
    ordersCreated.add(1);
    orderValue.add(25.50);
  }
}
```

### Tracking Error Types

```javascript theme={null}
import { Counter } from 'k6/metrics';

const errors4xx = new Counter('errors_4xx');
const errors5xx = new Counter('errors_5xx');

export default function() {
  const res = http.get('https://quickpizza.grafana.com/api/pizza');
  
  if (res.status >= 400 && res.status < 500) {
    errors4xx.add(1);
  } else if (res.status >= 500) {
    errors5xx.add(1);
  }
}
```

### Conditional Metrics

```javascript theme={null}
import { Trend } from 'k6/metrics';

const fastRequests = new Trend('fast_requests');
const slowRequests = new Trend('slow_requests');

export default function() {
  const res = http.get('https://quickpizza.grafana.com/');
  
  if (res.timings.duration < 200) {
    fastRequests.add(res.timings.duration);
  } else {
    slowRequests.add(res.timings.duration);
  }
}
```

## Best Practices

<Steps>
  <Step title="Use Built-in Metrics First">
    Built-in metrics cover most use cases. Only add custom metrics when necessary.
  </Step>

  <Step title="Choose the Right Metric Type">
    Use Counter for totals, Gauge for latest values, Trend for statistics, and Rate for success rates.
  </Step>

  <Step title="Add Meaningful Tags">
    Tag metrics to enable filtering and detailed analysis.
  </Step>

  <Step title="Combine Metrics with Thresholds">
    Use metrics with thresholds to define pass/fail criteria.
  </Step>
</Steps>

<Tip>
  Custom metrics are defined in the init context but recorded in the default function.
</Tip>

<Warning>
  Too many custom metrics can impact test performance and increase memory usage.
</Warning>

Metrics provide the quantitative data you need to understand system performance and make informed decisions about scalability and reliability.
