Add initial zapdriver implementation #1
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This moves some of blendle/go-logger#5 into a separate package.
I noticed that that Stackdriver implementation was actually incorrect for the use-case we have (which is Kubernetes-based logging, which does not use the Stackdriver error logging format, but instead uses the general LogEntry format).
This adds an easy-to-use general-purpose Stackdriver wrapper on top of Zap for our use-case.
README copy/pasted below:
⚡ Zapdriver
Blazing fast, Zap-based Stackdriver logging.
Usage
This package provides three building blocks to support the full array of
structured logging capabilities of Stackdriver:
The above components can be used separately, but to start, you can create a new
Zap logger with all of the above included:
The above functions give back a pointer to a
zap.Logger
object, so you can useZap like you've always done, except that it now logs in the proper
Stackdriver format.
You can also create a configuration struct, and build your logger from there:
Or, get the Zapdriver encoder, and build your own configuration struct from
that:
Read on to learn more about the available Stackdriver-specific log fields, and
how to use the above-mentioned components.
Special purpose logging fields
You can use the following fields to add extra information to your log entries.
These fields are parsed by Stackdriver to make it easier to query your logs or
to use the log details in the Stackdriver monitoring interface.
HTTP
Label
SourceLocation
Operation
HTTP
You can log HTTP request/response cycles using the following field:
You can either manually build the request payload:
Or, you can auto generate the struct, based on the available request and
response objects:
You are free to pass in
nil
for either the request or response object, if oneof them is unavailable to you at the point of logging. Any field depending on
one or the other will be omitted if
nil
is passed in.Note that there are some fields that are not populated by either the request or
response object, and need to be set manually:
ServerIP string
Latency string
CacheLookup bool
CacheHit bool
CacheValidatedWithOriginServer bool
CacheFillBytes string
If you have no need for those fields, the quickest way to get started is like
so:
Label
You can add a "label" to your payload as follows:
Note that underwater, this sets the key to
labels.<key>
. You need to be usingthe
zapdriver.Core
core for this to be converted to the proper format forStackdriver to recognize the labels.
See "Custom Stackdriver Zap core" for more details.
If you have a reason not to use the provided Core, you can still wrap labels in
the right
labels
namespace by using the available function:Like so:
Again, wrapping the
Label
calls inLabels
is not required if you use thesupplied Zap Core.
SourceLocation
You can add a source code location to your log lines to be picked up by
Stackdriver.
Note that you can set this manually, or use
zapdriver.Core
to automaticallyadd this. If you set it manually, and use
zapdriver.Core
, the manual callstack will be preserved over the automated one.
Note that the function signature equals that of the return values of
runtime.Caller()
. This allows you to catch the stack frame at one location,while logging it at a different location, like so:
If you use
zapdriver.Core
, the above use-case is the only use-case where youwould want to manually set the source location. In all other situations, you can
simply omit this field, and it will be added automatically, using the stack
frame at the location where the log line is triggered.
If you don't use
zapdriver.Core
, and still want to add the source location atthe frame of the triggered log line, you'd do it like this:
Operation
The
Operation
log field allows you to group log lines into a single"operation" performed by the application:
For a pair of logs that belong to the same operation, you should use the same
id
between them. Theproducer
is an arbitrary identifier that should beglobally unique amongst all the logs of all your applications (meaning it should
probably be the unique name of the current application). You should set
first
to true for the first log in the operation, and
last
to true for the final logof the operation.
Pre-configured Stackdriver-optimized encoder
The Stackdriver encoder maps all Zap log levels to the appropriate
Stackdriver-supported levels:
It also sets some of the default keys to use the right names, such as
timestamp
,severity
, andmessage
.You can use this encoder if you want to build your Zap logger configuration
manually:
For parity-sake, there's also
zapdriver.NewDevelopmentEncoderConfig()
, but itreturns the exact same encoder right now.
Custom Stackdriver Zap core
A custom Zap core is included in this package to support some special use-cases.
First of all, if you use
zapdriver.NewProduction()
(orNewDevelopment
) , youalready have this core enabled, so everything just works ™.
There are two use-cases which require this core:
If you use
zapdriver.Label("hello", "world")
, it will initially end up inyour log with the key
labels.hello
and valueworld
. Now if you have twolabels, you could also have
labels.hi
with valueuniverse
. This works as-is, but for this to be correctly parsed by Stackdriver as true "labels", you
need to use the Zapdriver core, so that both of these fields get rewritten,
to use the namespace
labels
, and use the keyshello
andhi
within thatnamespace. This is done automatically.
If you don't want to use
zapdriver.SourceLocation()
on every log call, youcan use this core for the source location to be automatically added to
each log entry.
When building a logger, you can inject the Zapdriver core as follows: