COREDNS-LOG(7)
π
COREDNS-LOG(7) β the log plugin, explained by your fave Unix bestie
okay so this is the coredns-log(7) page, and honestly? it's a whole vibe. it's the plugin that makes CoreDNS spill the tea about every query. let's get into it π«Ά
β¨ NAME β¨
log β enables query logging to standard output. that's it, that's the tweet. π
πΈ DESCRIPTION πΈ
so bestie, here's the deal: if you just slap log in there with nothing else, you dump all queries (plus the parts of the reply) straight onto standard output. there are options to tweak the output a lil bit if the default isn't giving what you need.
β οΈ heads up: for busy servers, logging will incur a performance hit. no cap, it's doing real work on every single query, so don't come crying to me when your hot server gets sweaty. π
also, important: enabling or disabling the log plugin only affects the query logging. any other logging from CoreDNS will show up regardless. so turning log off does not silence the whole building, just this one very loud roommate. π
π SYNTAX π
the absolute minimal version, no thoughts head empty:
log
with no arguments, a query log entry is written to stdout in the common log format for all requests. iconic. β¨
or, if you want/need slightly more control:
log [NAMES...] [FORMAT]
NAMESis the name list to match in order to be loggedFORMATis the log format to use (default is Common Log Format),{common}is used as a shortcut for the Common Log Format. You can also use{combined}for a format that adds the query opcode{>opcode}to the Common Log Format.
and you can further specify the classes of responses that get logged:
log [NAMES...] [FORMAT] {
class CLASSES...
}
CLASSESis a space-separated list of classes of responses that should be logged
the classes of responses have the following meaning, and yes i'm listing all of them because we don't skip:
- success: successful response β
- denial: either
NXDOMAINor nodata responses (Name exists, type does not). A nodata response sets the return code toNOERROR. - error:
SERVFAIL,NOTIMP,REFUSED, etc. Anything that indicates the remote server is not willing to resolve the request. π© - all: the default β nothing is specified. Using of this class means that all messages will be logged whatever we mix together with
"all".
if no class is specified, it defaults to all. slay, defaults. π
π¦ LOG FORMAT π¦
you can specify a custom log format with any placeholder values. log supports both request and response placeholders, which is lowkey the fun part.
the following place holders are supported β full list, no cuts:
{type}: qtype of the request{name}: qname of the request{class}: qclass of the request{proto}: protocol used (tcporudp){remote}: client's IP address, for IPv6 addresses these are enclosed in brackets:[::1]{local}: server's IP address, for IPv6 addresses these are enclosed in brackets:[::1]{size}: request size in bytes{port}: client's port{duration}: response duration{rcode}: response RCODE{rsize}: raw (uncompressed), response size (a client may receive a smaller response){>rflags}: response flags, each set flag will be displayed, e.g."aa, tc". This includes the qr bit as well{>bufsize}: the EDNS0 buffer size advertised in the query{>do}: is the EDNS0 DO (DNSSEC OK) bit set in the query{>id}: query ID{>opcode}: query OPCODE{common}: the default Common Log Format.{combined}: the Common Log Format with the query opcode.{/LABEL}: any metadata label is accepted as a place holder if it is enclosed between{/and}, the place holder will be replaced by the corresponding metadata value or the default value - if label is not defined. See the metadata plugin for more information.
and the default Common Log Format is, in all its glory:
{remote}:{port} - {>id} "{type} {class} {name} {proto} {size} {>do} {>bufsize}" {rcode} {>rflags} {rsize} {duration}
in the default text mode, each of these logs is output with log.Info, so a typical example looks like this:
[INFO] [::1]:50759 - 29008 "A IN example.org. udp 41 false 4096" NOERROR qr,rd,ra,ad 68 0.037990251s
look at that beautiful line. look at it. π₯Ή
β JSON OUTPUT β
start CoreDNS with -log-format=json to select JSON output for the entire process. and bestie, read this carefully: this is a command-line flag, not a Corefile directive. don't put it in your Corefile, i'm begging you. π -log-format=text is the default. the log plugin's name and response-class filters work identically in both modes, so nothing changes up there.
each query produces one JSON record with common fields time, level, msg, and plugin (always log for query records), plus these typed fields:
client_ipβ string β Client address, without brackets around IPv6 addressesclient_portβ number β Client portqnameβ string β Lowercase, fully qualified query name, in DNS presentation formatqtype,qclassβ string β Query type and class, including numeric forms for unknown valuesprotocolβ string βudportcp, as for{proto}id,opcodeβ number β Query ID and opcoderequest_sizeβ number β Request size in bytes, as for{size}dnssec_okβ boolean β Query's DNSSEC OK bitbufsizeβ number β Effective response buffer size, as for{>bufsize}rcodeβ string or null β Response RCODE, ornullif no DNS response was recordedresponse_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. and there's some nuance here so pay attention:
deferred errors (such asSERVFAIL) use the response CoreDNS will generate after the plugin chain returns. a dropped request hasrcode: null; it is not logged as a successful response. RawWritecalls 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. very "i contain multitudes" of it honestly. π§
for example, with log . "{name} {rcode}":
{"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}
one (1) perfect little JSON baddie. π
β¨ ADDITIONAL METADATA β¨
Okay so the log plugin adds these extra metadata bits so you can get granular differentiation between NOERROR denial messages and success messages β literally that specific. Theyβre mapped from plugin/pkg/response/classify.go and plugin/pkg/response/typify.go:
{/log/class}βsuccess,denial{/log/type}βNODATA,NXDOMAIN,NOERROR
And hereβs how that looks in a config, bestie:
. {
log . "{proto} Request: {name} {type} {/log/class} {/log/type}"
}
π EXAMPLES π
π Log all requests to stdout
. {
log
whoami
}
π¦ Custom log format, for all zones (.)
. {
log . "{proto} Request: {name} {type} {>id}"
}
πΈ Only log denials (NXDOMAIN and nodata) for example.org (and below)
. {
log example.org {
class denial
}
}
β¨ Log all queries which were not resolved successfully in the Combined Log Format
. {
log . {combined} {
class denial error
}
}
π Log all queries on which we did not get errors
. {
log . {
class denial success
}
}
π₯ Also, multiple statements can be OR-ed
Like, for example, we can rewrite the above case as following:
. {
log . {
class denial
class success
}
}
This icon of a page is serving source/version CoreDNS and date October 2026 energy, aka COREDNS-LOG(7) β mwah πβ¨
π¦ where this page comes from
- opensuse-leap 16.0: coredns-extras 1.15.0-bp160.1.1 Β· Apache-2.0 AND MPL-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms