# DNS-collector: a DNS telemetry pipeline that filters before it stores

> DNS-collector ingests queries and responses from your DNS servers over DNStap or live packet capture, discards noise at wire speed, enriches what is left with GeoIP and threat data, and streams it to Kafka, ClickHouse, Loki, Elasticsearch or Prometheus. It is written in Go, and the module path now carries a v3 suffix.

**dmachard/DNS-collector** — Grab your DNS logs, detect anomalies, and finally understand what's happening on your network. The missing piece between DNS servers and your data stack.

- Repository: https://github.com/dmachard/DNS-collector
- Website: https://dmachard.github.io/DNS-collector/
- Stars: 572 · Forks: 90
- Language: Go
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/dmachard-dns-collector

## Filter at the wire, not after the fact

DNS-collector is described as a lightweight tool that captures DNS queries and responses from your DNS servers, processes them intelligently, and sends clean data to your monitoring, analytics and security systems. The four capabilities are listed in the order they happen. It captures at scale, ingesting streams from BIND, PowerDNS, Unbound and others via the high-speed DNStap protocol or live wire packet capture. It filters and normalizes, discarding noise such as health checks, internal probes and spam at wire speed before anything reaches storage. It enriches on the fly, decorating records with GeoIP, ASN, threat intelligence, metadata and custom tags. And it streams everywhere, dispatching batched events to ClickHouse, Kafka, Loki, Elasticsearch, Syslog, Prometheus and more. The order is the design. The filtering step is what makes the rest affordable, because the cheapest place to drop a health check is before it has been serialised into an event.

## A pipeline config, and the smallest useful one

The quick start is a config file, and the example is short enough to read as a description of the model. You download the latest release and create a simple config.yml pipeline.

```yaml
pipelines:
  - name: tap
    dnstap:
      listen-ip: 0.0.0.0
      listen-port: 6000
    transforms:
      normalize:
        qname-lowercase: true
    routing-policy:
      forward: [ console ]
  - name: console
    stdout:
      mode: text
```

The vocabulary is worth learning because it is reused throughout. A pipeline has a name, one or more input collectors, a set of transforms, and a routing policy that says where the results go. Here the tap pipeline listens for DNStap on tcp/6000, applies a normalize transform that lowercases the query name, and forwards to a pipeline named console. The console pipeline writes to stdout in text mode. The default setup therefore listens on tcp/6000 for DNStap streams and outputs to stdout, and running it is one command.

```bash
./dnscollector -config config.yml
```

## The documentation is organised by the shape of the pipeline

The documentation index mirrors the architecture, and it is a good map of what the tool can do. There is a formats page covering supported output formats such as text, JSON, PCAP and Jinja2 templates, a complete configuration reference, a collectors page for input sources including the network packet sniffer and the DNStap server, and a loggers page for output destinations such as Kafka, Prometheus, syslog and Loki. There is a transformers page for data enrichment options, a Docker page for container deployment, and an examples page with ready to use configs. Then there are the platform pages, a sources and sinks page for integration with popular tools and DNS servers, and a page on enhanced DNStap features. The last two are performance pages, one for the REST API and Prometheus metrics and one for performance tuning.

## A Go module with a v3 path, and a wide dependency footprint

The module declaration is github.com/dmachard/go-dnscollector/v3, so the repository is the go-dnscollector project and the major version lives in the path rather than a tag prefix convention. The Go requirement is 1.26.5. The dependency list is long and reveals what the tool is made of. There are the author's own libraries for the moving parts, go-dnstap-protobuf for DNStap, go-powerdns-protobuf for PowerDNS, go-framestream for frame streams, go-clientsyslog for syslog output, go-logger for logging, go-netutils for network helpers and go-topmap for IP to ASN mapping. The third-party set covers the outputs and inputs: the IBM fluent-forward-go and sarama libraries for Fluentd and Kafka, Eclipse Paho for MQTT, the Grafana Loki client, InfluxDB's Go client, the Prometheus client, the OpenTelemetry SDK and OTLP trace exporters, Google gopacket for packet capture, the miekg DNS library, the MaxMind database reader for GeoIP, and nsq. The presence of both gopacket and the DNS library is what makes the live capture path possible.

## The container image is distroless, non-root and packed with upx

The Dockerfile shows the deployment story, and it is a careful one. The builder stage uses a Go Alpine image, installs git and upx, and builds with cgo disabled, trimming the path and stripping symbols, then compresses the binary with upx using the best and lzma methods. The runtime stage is a distroless static Debian 13 image running as the nonroot user, so there is no shell and no package manager in the image at all. The Dockerfile prepares a passwd and group entry for a user with uid and gid 1000 and creates the etc and var directories for the collector with the right ownership, then copies the binary and a default config into place. The entrypoint is the binary itself with the config path as the default command, and the three exposed ports are 6000 for DNStap, 8080 for the metrics and API surface, and 9165, which the compose file maps alongside 6000 and 8080.

## Tests, benchmarks, fuzzers and a count of them in the Makefile

The badges give the numbers and the Makefile gives the mechanism. There is a Go version badge requiring at least 1.26, a badge for 331 Go tests, one for 67 percent coverage and one for 113 microbenchmarks. The count-tests target lists and counts the tests, benchmarks and fuzzers in the repository by running the go test list command and counting entries by prefix, printing a breakdown of unit tests, benchmarks and fuzzers separately. That target exists for a reason, and it is a good one: the project wants the count to be visible so that it cannot quietly shrink. The same target distinguishes fuzzers from benchmarks, which tells you the DNS parsing paths are being fuzzed rather than only exercised by fixed inputs. Other targets cover linting, building, documentation serving, and the usual clean, and the build stamps the Prometheus common version and revision fields from the git describe output, the short commit and the branch.

## Conclusion

DNS-collector fits a team that runs its own DNS servers and wants query telemetry in the same system as the rest of its observability stack, especially if the volume of DNS noise would otherwise swamp that stack. It does not fit a team whose DNS is hosted elsewhere and who cannot install a collector next to it. Verify first that your DNS server can emit DNStap, since the wire capture path is a different and heavier mode, and read the anonymisation and filtering settings before you point it at a network with user data, because IP anonymisation and noise discarding both change what ends up in your logs.

## FAQ

### What does DNS-collector do?

It captures DNS queries and responses from your DNS servers, filters and normalizes them, enriches the records with GeoIP, ASN, threat intelligence, metadata and custom tags, and dispatches the results to monitoring, analytics and security systems. It ingests from BIND, PowerDNS, Unbound and others over the high-speed DNStap protocol or by live wire packet capture.

### How do I run DNS-collector for the first time?

Download the latest release and create a config.yml with a pipeline that listens for DNStap on tcp/6000, applies transforms, and forwards to a stdout logger, then run ./dnscollector -config config.yml. The default setup listens on tcp/6000 for DNStap streams and outputs to stdout.

### Where can DNS-collector send its data?

It dispatches batched events to ClickHouse, Kafka, Loki, Elasticsearch, Syslog, Prometheus and more. The documentation index lists the supported output formats as text, JSON, PCAP and Jinja2 among others, and it links a loggers page covering the output destinations.

### What are the system requirements for DNS-collector?

The Go module requires Go 1.26.5. The container image is built from a Go Alpine builder and runs on distroless static Debian as a non-root user with uid 1000, exposing ports 6000, 8080 and 9165, and the compose file maps those three ports to the host.

## Sources

- [dmachard/DNS-collector on GitHub](https://github.com/dmachard/DNS-collector)
- [License: MIT](https://github.com/dmachard/DNS-collector/blob/main/LICENSE)
- [Project website](https://dmachard.github.io/DNS-collector/)
- [README](https://github.com/dmachard/DNS-collector/blob/main/README.md)
- [Releases](https://github.com/dmachard/DNS-collector/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/dmachard-dns-collector
