mirror of
https://github.com/nshttpd/mikrotik-exporter.git
synced 2024-12-11 14:18:28 +01:00
328 lines
9.8 KiB
Go
328 lines
9.8 KiB
Go
|
// Copyright (c) 2016 Uber Technologies, Inc.
|
||
|
//
|
||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
// of this software and associated documentation files (the "Software"), to deal
|
||
|
// in the Software without restriction, including without limitation the rights
|
||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
// copies of the Software, and to permit persons to whom the Software is
|
||
|
// furnished to do so, subject to the following conditions:
|
||
|
//
|
||
|
// The above copyright notice and this permission notice shall be included in
|
||
|
// all copies or substantial portions of the Software.
|
||
|
//
|
||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
|
// THE SOFTWARE.
|
||
|
|
||
|
package zap_test
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"io/ioutil"
|
||
|
"log"
|
||
|
"os"
|
||
|
"time"
|
||
|
|
||
|
"go.uber.org/zap"
|
||
|
"go.uber.org/zap/zapcore"
|
||
|
)
|
||
|
|
||
|
func Example_presets() {
|
||
|
// Using zap's preset constructors is the simplest way to get a feel for the
|
||
|
// package, but they don't allow much customization.
|
||
|
logger := zap.NewExample() // or NewProduction, or NewDevelopment
|
||
|
defer logger.Sync()
|
||
|
|
||
|
const url = "http://example.com"
|
||
|
|
||
|
// In most circumstances, use the SugaredLogger. It's 4-10x faster than most
|
||
|
// other structured logging packages and has a familiar, loosely-typed API.
|
||
|
sugar := logger.Sugar()
|
||
|
sugar.Infow("Failed to fetch URL.",
|
||
|
// Structured context as loosely typed key-value pairs.
|
||
|
"url", url,
|
||
|
"attempt", 3,
|
||
|
"backoff", time.Second,
|
||
|
)
|
||
|
sugar.Infof("Failed to fetch URL: %s", url)
|
||
|
|
||
|
// In the unusual situations where every microsecond matters, use the
|
||
|
// Logger. It's even faster than the SugaredLogger, but only supports
|
||
|
// structured logging.
|
||
|
logger.Info("Failed to fetch URL.",
|
||
|
// Structured context as strongly typed fields.
|
||
|
zap.String("url", url),
|
||
|
zap.Int("attempt", 3),
|
||
|
zap.Duration("backoff", time.Second),
|
||
|
)
|
||
|
// Output:
|
||
|
// {"level":"info","msg":"Failed to fetch URL.","url":"http://example.com","attempt":3,"backoff":"1s"}
|
||
|
// {"level":"info","msg":"Failed to fetch URL: http://example.com"}
|
||
|
// {"level":"info","msg":"Failed to fetch URL.","url":"http://example.com","attempt":3,"backoff":"1s"}
|
||
|
}
|
||
|
|
||
|
func Example_basicConfiguration() {
|
||
|
// For some users, the presets offered by the NewProduction, NewDevelopment,
|
||
|
// and NewExample constructors won't be appropriate. For most of those
|
||
|
// users, the bundled Config struct offers the right balance of flexibility
|
||
|
// and convenience. (For more complex needs, see the AdvancedConfiguration
|
||
|
// example.)
|
||
|
//
|
||
|
// See the documentation for Config and zapcore.EncoderConfig for all the
|
||
|
// available options.
|
||
|
rawJSON := []byte(`{
|
||
|
"level": "debug",
|
||
|
"encoding": "json",
|
||
|
"outputPaths": ["stdout", "/tmp/logs"],
|
||
|
"errorOutputPaths": ["stderr"],
|
||
|
"initialFields": {"foo": "bar"},
|
||
|
"encoderConfig": {
|
||
|
"messageKey": "message",
|
||
|
"levelKey": "level",
|
||
|
"levelEncoder": "lowercase"
|
||
|
}
|
||
|
}`)
|
||
|
|
||
|
var cfg zap.Config
|
||
|
if err := json.Unmarshal(rawJSON, &cfg); err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
logger, err := cfg.Build()
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
defer logger.Sync()
|
||
|
|
||
|
logger.Info("logger construction succeeded")
|
||
|
// Output:
|
||
|
// {"level":"info","message":"logger construction succeeded","foo":"bar"}
|
||
|
}
|
||
|
|
||
|
func Example_advancedConfiguration() {
|
||
|
// The bundled Config struct only supports the most common configuration
|
||
|
// options. More complex needs, like splitting logs between multiple files
|
||
|
// or writing to non-file outputs, require use of the zapcore package.
|
||
|
//
|
||
|
// In this example, imagine we're both sending our logs to Kafka and writing
|
||
|
// them to the console. We'd like to encode the console output and the Kafka
|
||
|
// topics differently, and we'd also like special treatment for
|
||
|
// high-priority logs.
|
||
|
|
||
|
// First, define our level-handling logic.
|
||
|
highPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
||
|
return lvl >= zapcore.ErrorLevel
|
||
|
})
|
||
|
lowPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
||
|
return lvl < zapcore.ErrorLevel
|
||
|
})
|
||
|
|
||
|
// Assume that we have clients for two Kafka topics. The clients implement
|
||
|
// zapcore.WriteSyncer and are safe for concurrent use. (If they only
|
||
|
// implement io.Writer, we can use zapcore.AddSync to add a no-op Sync
|
||
|
// method. If they're not safe for concurrent use, we can add a protecting
|
||
|
// mutex with zapcore.Lock.)
|
||
|
topicDebugging := zapcore.AddSync(ioutil.Discard)
|
||
|
topicErrors := zapcore.AddSync(ioutil.Discard)
|
||
|
|
||
|
// High-priority output should also go to standard error, and low-priority
|
||
|
// output should also go to standard out.
|
||
|
consoleDebugging := zapcore.Lock(os.Stdout)
|
||
|
consoleErrors := zapcore.Lock(os.Stderr)
|
||
|
|
||
|
// Optimize the Kafka output for machine consumption and the console output
|
||
|
// for human operators.
|
||
|
kafkaEncoder := zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
|
||
|
consoleEncoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
|
||
|
|
||
|
// Join the outputs, encoders, and level-handling functions into
|
||
|
// zapcore.Cores, then tee the four cores together.
|
||
|
core := zapcore.NewTee(
|
||
|
zapcore.NewCore(kafkaEncoder, topicErrors, highPriority),
|
||
|
zapcore.NewCore(consoleEncoder, consoleErrors, highPriority),
|
||
|
zapcore.NewCore(kafkaEncoder, topicDebugging, lowPriority),
|
||
|
zapcore.NewCore(consoleEncoder, consoleDebugging, lowPriority),
|
||
|
)
|
||
|
|
||
|
// From a zapcore.Core, it's easy to construct a Logger.
|
||
|
logger := zap.New(core)
|
||
|
defer logger.Sync()
|
||
|
logger.Info("constructed a logger")
|
||
|
}
|
||
|
|
||
|
func ExampleNamespace() {
|
||
|
logger := zap.NewExample()
|
||
|
defer logger.Sync()
|
||
|
|
||
|
logger.With(
|
||
|
zap.Namespace("metrics"),
|
||
|
zap.Int("counter", 1),
|
||
|
).Info("tracked some metrics")
|
||
|
// Output:
|
||
|
// {"level":"info","msg":"tracked some metrics","metrics":{"counter":1}}
|
||
|
}
|
||
|
|
||
|
func ExampleNewStdLog() {
|
||
|
logger := zap.NewExample()
|
||
|
defer logger.Sync()
|
||
|
|
||
|
std := zap.NewStdLog(logger)
|
||
|
std.Print("standard logger wrapper")
|
||
|
// Output:
|
||
|
// {"level":"info","msg":"standard logger wrapper"}
|
||
|
}
|
||
|
|
||
|
func ExampleRedirectStdLog() {
|
||
|
logger := zap.NewExample()
|
||
|
defer logger.Sync()
|
||
|
|
||
|
undo := zap.RedirectStdLog(logger)
|
||
|
defer undo()
|
||
|
|
||
|
log.Print("redirected standard library")
|
||
|
// Output:
|
||
|
// {"level":"info","msg":"redirected standard library"}
|
||
|
}
|
||
|
|
||
|
func ExampleReplaceGlobals() {
|
||
|
logger := zap.NewExample()
|
||
|
defer logger.Sync()
|
||
|
|
||
|
undo := zap.ReplaceGlobals(logger)
|
||
|
defer undo()
|
||
|
|
||
|
zap.L().Info("replaced zap's global loggers")
|
||
|
// Output:
|
||
|
// {"level":"info","msg":"replaced zap's global loggers"}
|
||
|
}
|
||
|
|
||
|
func ExampleAtomicLevel() {
|
||
|
atom := zap.NewAtomicLevel()
|
||
|
|
||
|
// To keep the example deterministic, disable timestamps in the output.
|
||
|
encoderCfg := zap.NewProductionEncoderConfig()
|
||
|
encoderCfg.TimeKey = ""
|
||
|
|
||
|
logger := zap.New(zapcore.NewCore(
|
||
|
zapcore.NewJSONEncoder(encoderCfg),
|
||
|
zapcore.Lock(os.Stdout),
|
||
|
atom,
|
||
|
))
|
||
|
defer logger.Sync()
|
||
|
|
||
|
logger.Info("info logging enabled")
|
||
|
|
||
|
atom.SetLevel(zap.ErrorLevel)
|
||
|
logger.Info("info logging disabled")
|
||
|
// Output:
|
||
|
// {"level":"info","msg":"info logging enabled"}
|
||
|
}
|
||
|
|
||
|
func ExampleAtomicLevel_config() {
|
||
|
// The zap.Config struct includes an AtomicLevel. To use it, keep a
|
||
|
// reference to the Config.
|
||
|
rawJSON := []byte(`{
|
||
|
"level": "info",
|
||
|
"outputPaths": ["stdout"],
|
||
|
"errorOutputPaths": ["stderr"],
|
||
|
"encoding": "json",
|
||
|
"encoderConfig": {
|
||
|
"messageKey": "message",
|
||
|
"levelKey": "level",
|
||
|
"levelEncoder": "lowercase"
|
||
|
}
|
||
|
}`)
|
||
|
var cfg zap.Config
|
||
|
if err := json.Unmarshal(rawJSON, &cfg); err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
logger, err := cfg.Build()
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
defer logger.Sync()
|
||
|
|
||
|
logger.Info("info logging enabled")
|
||
|
|
||
|
cfg.Level.SetLevel(zap.ErrorLevel)
|
||
|
logger.Info("info logging disabled")
|
||
|
// Output:
|
||
|
// {"level":"info","message":"info logging enabled"}
|
||
|
}
|
||
|
|
||
|
func ExampleLogger_Check() {
|
||
|
logger := zap.NewExample()
|
||
|
defer logger.Sync()
|
||
|
|
||
|
if ce := logger.Check(zap.DebugLevel, "debugging"); ce != nil {
|
||
|
// If debug-level log output isn't enabled or if zap's sampling would have
|
||
|
// dropped this log entry, we don't allocate the slice that holds these
|
||
|
// fields.
|
||
|
ce.Write(
|
||
|
zap.String("foo", "bar"),
|
||
|
zap.String("baz", "quux"),
|
||
|
)
|
||
|
}
|
||
|
|
||
|
// Output:
|
||
|
// {"level":"debug","msg":"debugging","foo":"bar","baz":"quux"}
|
||
|
}
|
||
|
|
||
|
func ExampleLogger_Named() {
|
||
|
logger := zap.NewExample()
|
||
|
defer logger.Sync()
|
||
|
|
||
|
// By default, Loggers are unnamed.
|
||
|
logger.Info("no name")
|
||
|
|
||
|
// The first call to Named sets the Logger name.
|
||
|
main := logger.Named("main")
|
||
|
main.Info("main logger")
|
||
|
|
||
|
// Additional calls to Named create a period-separated path.
|
||
|
main.Named("subpackage").Info("sub-logger")
|
||
|
// Output:
|
||
|
// {"level":"info","msg":"no name"}
|
||
|
// {"level":"info","logger":"main","msg":"main logger"}
|
||
|
// {"level":"info","logger":"main.subpackage","msg":"sub-logger"}
|
||
|
}
|
||
|
|
||
|
func ExampleWrapCore_replace() {
|
||
|
// Replacing a Logger's core can alter fundamental behaviors. For example,
|
||
|
// example, it can convert a Logger to a no-op.
|
||
|
nop := zap.WrapCore(func(zapcore.Core) zapcore.Core {
|
||
|
return zapcore.NewNopCore()
|
||
|
})
|
||
|
|
||
|
logger := zap.NewExample()
|
||
|
defer logger.Sync()
|
||
|
|
||
|
logger.Info("working")
|
||
|
logger.WithOptions(nop).Info("no-op")
|
||
|
logger.Info("original logger still works")
|
||
|
// Output:
|
||
|
// {"level":"info","msg":"working"}
|
||
|
// {"level":"info","msg":"original logger still works"}
|
||
|
}
|
||
|
|
||
|
func ExampleWrapCore_wrap() {
|
||
|
// Wrapping a Logger's core can extend its functionality. As a trivial
|
||
|
// example, it can double-write all logs.
|
||
|
doubled := zap.WrapCore(func(c zapcore.Core) zapcore.Core {
|
||
|
return zapcore.NewTee(c, c)
|
||
|
})
|
||
|
|
||
|
logger := zap.NewExample()
|
||
|
defer logger.Sync()
|
||
|
|
||
|
logger.Info("single")
|
||
|
logger.WithOptions(doubled).Info("doubled")
|
||
|
// Output:
|
||
|
// {"level":"info","msg":"single"}
|
||
|
// {"level":"info","msg":"doubled"}
|
||
|
// {"level":"info","msg":"doubled"}
|
||
|
}
|