How to Create a StatsD UDP Metric Mock Server in Python

Run a lightweight mock UDP server that captures StatsD metrics over a short window for local testing.

Medium Python 3.9+ Aug 9, 2026 Observability & SRE 13 views 0 copies

Python code

41 lines
Python 3.9+
import socket
import threading
import time


def start_mock_statsd_server(host="127.0.0.1", port=8125, timeout=3):
    """Run a mock StatsD UDP server that captures metrics for a short window."""
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind((host, port))
    sock.settimeout(timeout)
    metrics = []

    def collect():
        while True:
            try:
                data, _ = sock.recvfrom(4096)
                metrics.append(data.decode("utf-8").strip())
            except socket.timeout:
                break

    thread = threading.Thread(target=collect, daemon=True)
    thread.start()
    thread.join(timeout + 1)
    sock.close()
    return metrics


if __name__ == "__main__":
    # Simulate a client sending metrics while the mock server is listening
    mock_thread = threading.Thread(target=lambda: time.sleep(0.2))
    mock_thread.start()
    results = start_mock_statsd_server(timeout=1)

    client_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    client_sock.sendto(b"page.visits:5|c", ("127.0.0.1", 8125))
    client_sock.sendto(b"api.latency:124|ms", ("127.0.0.1", 8125))
    client_sock.sendto(b"errors:1|c", ("127.0.0.1", 8125))
    client_sock.close()
    mock_thread.join()

    print("Captured metrics:", results)

Output

stdout
Captured metrics: ['page.visits:5|c', 'api.latency:124|ms', 'errors:1|c']

How it works

The mock server binds a UDP socket to a local port and listens until the timeout expires. recvfrom blocks until datagrams arrive or the socket times out, incrementally storing each decoded metric string. A daemon thread keeps collecting in the background while the main flow can test client behavior concurrently. This pattern works cleanly because UDP is fire-and-forget — no acknowledgment handshake — making it ideal for lightweight, in-process metric validation. The explicit sett timeout guarantees the server doesn't hang forever, enabling deterministic test runs.

Common mistakes

  • Forgetting to call `sock.settimeout` — the server blocks forever without a timeout
  • Sending datagrams after the mock exits — the collection window ends once `join` returns
  • Binding to the wrong host (0.0.0.0 vs 127.0.0.1) when testing from external threads
  • Not reusing the same port — UDP sockets require a unique bind unless multiple sockets reuse the address

Variations

  1. Use a context manager with `with socket.socket(...)` to auto-close the socket.
  2. Collect metrics into a list inside a lock to protect concurrent thread access.

Real-world use cases

  • Simulating StatsD servers in integration tests to assert that app metrics are emitted correctly.
  • Validating metrics format and content in CI before deploying code that sends observability telemetry.
  • Building a lightweight traffic generator to exercise metric handling paths without a real metrics backend.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Observability & SRE

Related tutorials and quizzes for this topic.