COREDNS-LOG(7)

πŸ“¦
version 1.15.0 Β· 3 versions
, in opensuse-leap 16.0

πŸ’… 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]
  • NAMES is the name list to match in order to be logged
  • FORMAT is 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...
}
  • CLASSES is 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 NXDOMAIN or nodata responses (Name exists, type does not). A nodata response sets the return code to NOERROR.
  • 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 (tcp or udp)
  • {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 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. and there's some nuance here so pay attention:

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. 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