Open-Source Wikis

/

CoreDNS

/

How to monitor

coredns/coredns

How to monitor

CoreDNS exposes three orthogonal observability surfaces — metrics, logs, and traces — plus dnstap for structured query/response capture and /health and /ready endpoints for orchestrators. This page is the operator-facing overview; the underlying plugins are documented in Plugins → Observability.

Quick recipe

A practical Corefile for production:

. {
    metadata
    errors
    log . "{remote} {name} {type} {rcode} {duration}"
    cache
    forward . 8.8.8.8 1.1.1.1 {
        max_concurrent 1000
    }
    prometheus :9153
    health :8080 {
        lameduck 5s
    }
    ready :8181
    pprof :6060        # optional, useful when chasing a regression
}

This loads everything most operators want: structured access logs, error reporting, Prometheus metrics, an HTTP health endpoint with lameduck, an HTTP readiness endpoint, and (optional) pprof. The metadata line is what gives log access to enriched per-request values.

Metrics

The prometheus plugin exposes /metrics on its configured listener (default :9153). The metric set is documented in plugin/metrics/vars/report.go.

Core query metrics

Metric Type Labels Meaning
coredns_dns_requests_total Counter server, zone, view, proto, family, type One per request received
coredns_dns_responses_total Counter server, zone, view, rcode, plugin One per reply sent, attributed to the plugin that produced it
coredns_dns_request_duration_seconds Histogram server, zone, view Latency from arrival to reply
coredns_dns_request_size_bytes Histogram server, zone, view, proto Inbound DNS message size
coredns_dns_response_size_bytes Histogram server, zone, view, proto Outbound DNS message size
coredns_dns_request_do_total Counter server, view Requests with the DO bit set
coredns_dns_request_type_total (deprecated, use requests_total)
coredns_panics_total Counter Plugin panics caught by recover()
coredns_build_info Gauge (1) version, revision, goversion Build metadata
coredns_health_request_duration_seconds Histogram Self-check latency from health

The plugin label on responses_total is the killer feature: it tells you which plugin in the chain produced the answer. So responses_total{plugin="cache"} is your hit count and responses_total{plugin="forward"} is your miss/forward count.

Per-plugin metrics

Many plugins ship their own metrics. A subset:

Plugin Metrics
cache coredns_cache_hits_total, coredns_cache_misses_total, coredns_cache_entries, coredns_cache_drops_total
forward coredns_forward_request_duration_seconds, coredns_forward_responses_total{rcode}, coredns_forward_healthcheck_failures_total, coredns_forward_max_concurrent_rejects_total
kubernetes coredns_kubernetes_dns_programming_duration_seconds, coredns_kubernetes_dns_endpoints_total
acl coredns_acl_blocked_responses_total
dnssec coredns_dnssec_cache_size, coredns_dnssec_cache_hits_total
metadata (none — instead other plugins read its values)
prometheus (the plugin itself; /metrics is its output)

Each plugin's metrics file (plugin/<name>/metrics.go) is the source of truth. Bumping a metric name is a backward-incompatible change handled by the deprecation policy described in Deployment.

Useful Grafana queries

# QPS
sum(rate(coredns_dns_requests_total[1m])) by (server)

# Cache hit ratio
sum(rate(coredns_dns_responses_total{plugin="cache"}[5m]))
/ sum(rate(coredns_dns_responses_total[5m]))

# 99th-percentile request latency
histogram_quantile(0.99,
  sum(rate(coredns_dns_request_duration_seconds_bucket[5m])) by (le, server))

# Forward upstream errors
sum(rate(coredns_forward_responses_total{rcode!="NOERROR"}[5m])) by (rcode)

Logs

Two plugins:

  • log prints one line per request. Configurable format with replacer placeholders ({remote}, {name}, {type}, {rcode}, {rsize}, {duration}, {>id}, {>do}, {>port}, {plugin}).
  • errors prints one line per plugin error and rate-limits identical error groups via consolidate.

Class filters on log (success, denial, error, all) let you log only NXDOMAINs in production.

Format strings can be JSON for ingestion into a log pipeline:

log . `{"remote":"{remote}","name":"{name}","type":"{type}","rcode":"{rcode}","duration":"{duration}"}`

Tracing

The trace plugin emits OpenTracing-style spans for each query and each downstream plugin call. Two backends:

  • Zipkintrace zipkin localhost:9411
  • Datadogtrace datadog localhost:8126

OpenTelemetry support is in progress; check the plugin README for the latest status.

A trace contains one span per plugin in the chain. If your forward plugin is suddenly slow, the trace tells you whether it's the upstream RTT, the connection pool, or one of the wrapping plugins.

dnstap

Binary structured query/response capture, framed via dnstap. Used when:

  • You need exactly the bytes that hit the server (logs are derived from dns.Msg).
  • You want machine-readable samples for offline analysis.
  • You're correlating CoreDNS behaviour with an upstream resolver's behaviour (the forward plugin emits forward_query/forward_response events).
dnstap unix:///var/run/dnstap.sock full
forward . 8.8.8.8

full includes the message payload (otherwise only the metadata is emitted). Read the socket with dnstap's CLI tool.

Health and readiness

  • /health (default :8080) returns 200 OK while the process is alive. Use this for liveness probes. With lameduck DURATION the endpoint stays 200 OK for the window after shutdown begins, so a load balancer can drain.
  • /ready (default :8181) returns 200 OK only when every plugin's Readiness check passes. Use this for readiness probes. The kubernetes plugin reports not-ready until the initial informer sync completes; forward reports not-ready while every upstream is failing health checks.

pprof

pprof :6060

Standard Go pprof endpoints. Useful when chasing a memory or goroutine leak in production. Profile types: profile (CPU), heap, allocs, goroutine, block, mutex. Disable in production builds where the diagnostic surface is a concern.

Putting it together

A complete monitoring deployment for a Kubernetes cluster:

Source Sink
prometheus :9153/metrics Prometheus scrape
log to stdout Container log driver → ELK/Loki
errors to stdout Same
dnstap unix://... dnstap collector → Kafka
trace zipkin ... Zipkin/OTel collector
health :8080 with lameduck livenessProbe
ready :8181 readinessProbe

Most production deployments do not need all of these. Metrics + access logs + health/ready are the minimum; trace and dnstap are situational.

Reload-safe metric semantics

When a Corefile reload happens, the metrics process keeps running (it's process-wide). Counters do not reset. Per-zone labels are added/removed as AddZone/RemoveZone are called by the new server set. Histograms inherit their accumulated buckets. The coredns_build_info gauge stays at 1; only version/revision would change after a binary swap.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

How to monitor – CoreDNS wiki | Factory