mirror of
https://github.com/coredns/coredns.git
synced 2026-10-09 03:55:21 -04:00
Add opt-in JSON logging with structured DNS query fields (#8553)
* plugin/pkg/log: add opt-in JSON logging backend Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com> * plugin/log: emit typed query records in JSON mode Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com> * coremain: expose process-wide JSON logging Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com> --------- Signed-off-by: houyuwushang <liuluoqianqiu@outlook.com>
This commit is contained in:
@@ -88,12 +88,51 @@ The default Common Log Format is:
|
||||
`{remote}:{port} - {>id} "{type} {class} {name} {proto} {size} {>do} {>bufsize}" {rcode} {>rflags} {rsize} {duration}`
|
||||
~~~
|
||||
|
||||
Each of these logs will be outputted with `log.Infof`, so a typical example looks like this:
|
||||
In the default text mode, each of these logs is output with `log.Info`, so a typical example looks like this:
|
||||
|
||||
~~~ txt
|
||||
[INFO] [::1]:50759 - 29008 "A IN example.org. udp 41 false 4096" NOERROR qr,rd,ra,ad 68 0.037990251s
|
||||
~~~
|
||||
|
||||
## JSON Output
|
||||
|
||||
Start CoreDNS with `-log-format=json` to select JSON output for the entire process.
|
||||
This is a command-line flag, not a Corefile directive. `-log-format=text` is the default.
|
||||
The `log` plugin's name and response-class filters work identically in both modes.
|
||||
|
||||
Each query produces one JSON record with common fields `time`, `level`, `msg`, and
|
||||
`plugin` (always `log` for query records), plus these typed fields:
|
||||
|
||||
| Field | Type | Meaning |
|
||||
| --- | --- | --- |
|
||||
| `client_ip` | string | Client address, without brackets around IPv6 addresses |
|
||||
| `client_port` | number | Client port |
|
||||
| `qname` | string | Lowercase, fully qualified query name, in DNS presentation format |
|
||||
| `qtype`, `qclass` | string | Query type and class, including numeric forms for unknown values |
|
||||
| `protocol` | string | `udp` or `tcp`, as for `{proto}` |
|
||||
| `id`, `opcode` | number | Query ID and opcode |
|
||||
| `request_size` | number | Request size in bytes, as for `{size}` |
|
||||
| `dnssec_ok` | boolean | Query's DNSSEC OK bit |
|
||||
| `bufsize` | number | Effective response buffer size, as for `{>bufsize}` |
|
||||
| `rcode` | string or null | Response RCODE, or null if no DNS response was recorded |
|
||||
| `response_size` | number | Recorded response size in bytes, as for `{rsize}` |
|
||||
| `duration_seconds` | number | Elapsed handling time in seconds |
|
||||
|
||||
As in text mode, response sizes describe recorded, uncompressed messages, not
|
||||
necessarily the bytes delivered to the client. Deferred errors (such as SERVFAIL)
|
||||
use the response CoreDNS will generate after the plugin chain returns. A dropped
|
||||
request has `rcode: null`; it is not logged as a successful response. Raw `Write`
|
||||
calls contribute to the size but do not provide a decoded response RCODE.
|
||||
|
||||
`FORMAT` still controls `msg`, including custom formats and metadata placeholders.
|
||||
It does not replace the JSON schema or define new top-level fields. The DNS fields
|
||||
come directly from the request and response, not from parsing `msg`. For example,
|
||||
with `log . "{name} {rcode}"`:
|
||||
|
||||
```json
|
||||
{"time":"2026-09-15T08:00:00Z","level":"INFO","msg":"example.org. NOERROR","plugin":"log","client_ip":"127.0.0.1","client_port":40212,"qname":"example.org.","qtype":"A","qclass":"IN","protocol":"udp","id":42,"opcode":0,"request_size":29,"dnssec_ok":false,"bufsize":512,"rcode":"NOERROR","response_size":29,"duration_seconds":0.001}
|
||||
```
|
||||
|
||||
## Additional metadata
|
||||
|
||||
The log plugin adds the following metadata to allow for granular differentiation of NOERROR denial vs success messages. These are mapped from `plugin/pkg/response/classify.go` and `plugin/pkg/response/typify.go`.
|
||||
|
||||
Reference in New Issue
Block a user