Files
coredns/plugin/log/json.go
houyuwushang b93e449b2f 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>
2026-09-16 17:50:39 -07:00

45 lines
1.2 KiB
Go

package log
import (
"log/slog"
"strconv"
"time"
"github.com/coredns/coredns/plugin/pkg/dnstest"
clog "github.com/coredns/coredns/plugin/pkg/log"
"github.com/coredns/coredns/request"
"github.com/miekg/dns"
)
func logJSON(msg string, state request.Request, rr *dnstest.Recorder) {
// A missing response is not NOERROR (for example an ACL drop). Deferred
// errors have already been synthesized by ServeDNS, just as in text mode.
rcode := slog.Any("rcode", nil)
if rr.Msg != nil {
rc := dns.RcodeToString[rr.Rcode]
if rc == "" {
rc = strconv.Itoa(rr.Rcode)
}
rcode = slog.String("rcode", rc)
}
port, _ := strconv.Atoi(state.Port())
clog.InfoAttrs(msg,
slog.String("plugin", "log"),
slog.String("client_ip", state.IP()),
slog.Int("client_port", port),
slog.String("qname", state.Name()),
slog.String("qtype", state.Type()),
slog.String("qclass", state.Class()),
slog.String("protocol", state.Proto()),
slog.Int("id", int(state.Req.Id)),
slog.Int("opcode", state.Req.Opcode),
slog.Int("request_size", state.Len()),
slog.Bool("dnssec_ok", state.Do()),
slog.Int("bufsize", state.Size()),
rcode,
slog.Int("response_size", rr.Len),
slog.Float64("duration_seconds", time.Since(rr.Start).Seconds()),
)
}