From 63d976334d27192479bde6e99b6b5cd7a7cc3787 Mon Sep 17 00:00:00 2001 From: Danprot Date: Tue, 18 Oct 2022 16:16:09 +0300 Subject: [PATCH] klogga v0.3 (#10) klogga v0.3 --- AUTHORS.md | 1 + LICENSE.TXT | 4 +- README.md | 91 +++- adapters/fx/fx_adapter.go | 21 +- adapters/fx/runner.go | 26 +- adapters/grpc/grpc_adapter.go | 2 - batcher/batcher.go | 16 +- batcher/batcher_test.go | 39 ++ examples/basic_app/main.go | 5 +- examples/fx_app/main.go | 60 +++ exporter.go | 3 + exporters/otel/otel_exporter.go | 6 +- exporters/otel/readme.md | 1 + exporters/postgres/pg_exporter.go | 130 +++--- exporters/postgres/pg_exporter_test.go | 35 ++ .../postgres/pgconnector/pg_example_test.go | 4 + exporters/postgres/postgres_types.go | 22 +- exporters/postgres/table_schema.go | 18 +- exporters/readme.md | 1 + factory.go | 8 +- go.mod | 43 +- go.sum | 91 ++-- legal_notices.txt | 389 +++++++++++++----- log_levels.go | 3 + span.go | 151 +++---- span_defaults.go | 10 + span_fuzz_test.go | 18 + span_json.go | 42 ++ span_opt.go | 28 ++ span_test.go | 2 +- testdata/log.std.out.v5/logger.go | 21 + testdata/loggers.v4.0.1/logger.go | 21 + testdata/loggers.v4/logger.go | 21 + testdata/loggers/2.2.2/logger.go | 21 + testdata/loggers/logger.go | 21 + testdata/loggers/v2.1/logger.go | 21 + testdata/loggers/v2/logger.go | 21 + testdata/loggersv3/logger.go | 21 + testdata/nested/logger.go | 21 + testdata/nested/very/deep/logger.go | 21 + .../nested/very/deep/v4/black/hole/logger.go | 21 + .../deep/v4/black/hole/v6/loggers/logger.go | 21 + .../v4/black/hole/v6/loggers/v7/logger.go | 21 + testdata/nested/very/deep/v4/black/logger.go | 21 + testdata/nested/very/logger.go | 21 + testdata/package_test.go | 79 ++++ testdata/parent/child/child.go | 7 + testdata/parent/parent.go | 21 + testdata/testpkg/v2/span_test.go | 11 + testdata/testpkg/v2/testpkg.go | 11 + util/defaults.go | 10 + util/errs/errs_test.go | 3 +- util/reflectutil/reflectutil.go | 117 +++++- util/reflectutil/reflectutil_test.go | 37 +- util/testutil/timeout.go | 10 +- utils.go | 2 + 56 files changed, 1504 insertions(+), 389 deletions(-) create mode 100644 examples/fx_app/main.go create mode 100644 exporters/otel/readme.md create mode 100644 exporters/readme.md create mode 100644 span_defaults.go create mode 100644 span_fuzz_test.go create mode 100644 span_json.go create mode 100644 testdata/log.std.out.v5/logger.go create mode 100644 testdata/loggers.v4.0.1/logger.go create mode 100644 testdata/loggers.v4/logger.go create mode 100644 testdata/loggers/2.2.2/logger.go create mode 100644 testdata/loggers/logger.go create mode 100644 testdata/loggers/v2.1/logger.go create mode 100644 testdata/loggers/v2/logger.go create mode 100644 testdata/loggersv3/logger.go create mode 100644 testdata/nested/logger.go create mode 100644 testdata/nested/very/deep/logger.go create mode 100644 testdata/nested/very/deep/v4/black/hole/logger.go create mode 100644 testdata/nested/very/deep/v4/black/hole/v6/loggers/logger.go create mode 100644 testdata/nested/very/deep/v4/black/hole/v6/loggers/v7/logger.go create mode 100644 testdata/nested/very/deep/v4/black/logger.go create mode 100644 testdata/nested/very/logger.go create mode 100644 testdata/package_test.go create mode 100644 testdata/parent/child/child.go create mode 100644 testdata/parent/parent.go create mode 100644 testdata/testpkg/v2/span_test.go create mode 100644 testdata/testpkg/v2/testpkg.go create mode 100644 util/defaults.go diff --git a/AUTHORS.md b/AUTHORS.md index 6ba4018..92d0363 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -2,3 +2,4 @@ The following authors have created the source code of "klogga"
published and distributed by AO Kaspersky Lab as the owner:
Danila Protsenko
+Artem Doktor
diff --git a/LICENSE.TXT b/LICENSE.TXT index 6c17d08..c75ebc4 100644 --- a/LICENSE.TXT +++ b/LICENSE.TXT @@ -1,6 +1,8 @@ MIT License -Copyright (c) 2021 klogga contributors +Copyright (c) 2022 AO Kaspersky Lab +Copyright (c) 2022 klogga contributors +All Rights Reserved Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 979afd0..4ab254c 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,91 @@ # Introduction Opinionated logging-audit-tracing library. -Data collected via klogga can be configured to be exported to different sources, including traditional text logs, but with emphasis on structured storages, primarily time-series databases and Open Telemetry. +Data collected via **klogga** can be configured to be exported to different sources, including traditional text logs, but with emphasis on structured storages, primarily time-series databases and Open Telemetry. + +The ideology is explained here (in russian) [Logging as fact-stream](https://www.youtube.com/watch?v=1lcKzy6j6-k) + +**klogga** is in development and as of yet does not even have a 1.0 release. +API is subject to changes, although we do not expect any. +It is used extensively in Kaspersky internal projects written in go. # Getting Started -import klogga -configure your root tracer, don't forget to use batcher for buffered traces -see examples/tracers_tree.go +## Basic +Import klogga, configure your root tracer, don't forget to use batcher for buffered traces +see [examples](examples/basic_app/main.go) + +```go +package main + +import ( + "context" + "github.com/KasperskyLab/klogga" + "github.com/KasperskyLab/klogga/util" + "time" +) + +func main() { + // kreating a factory, with the simplest exporter + tf := util.DefaultFactory() + + // kreating a tracer with a package name + trs := tf.NamedPkg() + + // starting a span + // for now, we'll ignore context + span, _ := klogga.Start(context.Background()) + // span will be written on func exit + defer trs.Finish(span) + + // tag - potentially indexed + span.Tag("app", "hello-world") + // value - for metrics, or bigger values + span.Val("meaning", 42) + // sleep a bit, to have us some non-zero duration + time.Sleep(154 * time.Millisecond) +} +``` +OUTPUT: +``` +2022-02-03 04:05:06.789 I main [main.] main() (155.17ms); app:'hello-world'; meaning:'42'; id: 65C6p2Mq2N4; trace: 4nxwjs5WR9G9A-1-dw4cqA +``` + +## Extended + +**klogga** comes with [fx](https://github.com/uber-go/fx) integration.
+See [fx example](examples/fx_app/main.go) + + +# Features and ideas +This list will be covered and structured in the future. + +- logging basic information automatically without manual setup +- logging code information for easy search (uses reflection) +- tracing support: parent-child spans and trace-id +- opentelemetry support +- TODO go fuzz tests +- TODO trace information propagation support for HTTP, GRPC +- TODO transport support +- TODO postgres type mapping customization +- TODO span serialization to protobuf +- TODO elasticsearch exporter (if opentelemetry is not enough) +- TODO more docs for postgreSQL & timescaleDB integration +- TODO increase test coverage (~60% to ~80%) + + +# Running tests +## Unit test +Unit tests do not require any environment, all tests that require environment will be skipped +```shell +go test ./... +``` + + +## Integration tests +Postgresql (timescaleDB) tests can be run on any empty database. +Tests use environment variable KLOGGA_PG_CONNECTION_STRING to connect to PG. +Use [docker-compose.yml](docker-compose.yml) to start default instance. +Default setup: +```shell +podman-compose up -d +KLOGGA_PG_CONNECTION_STRING='user=postgres password=postgres sslmode=disable' go test ./... +``` diff --git a/adapters/fx/fx_adapter.go b/adapters/fx/fx_adapter.go index 347e500..044d32b 100644 --- a/adapters/fx/fx_adapter.go +++ b/adapters/fx/fx_adapter.go @@ -22,18 +22,18 @@ func (t fxTracer) LogEvent(event fxevent.Event) { span.Tag("event", reflect.TypeOf(event).String()) switch e := event.(type) { case *fxevent.OnStartExecuting: - span.OverrideName(e.CallerName).Tag("callee", e.FunctionName) + span.OverrideName("OnStartExecuting").Tag("caller", e.CallerName).Tag("callee", e.FunctionName) case *fxevent.OnStartExecuted: - span.OverrideName(e.CallerName).Tag("callee", e.FunctionName) + span.OverrideName("OnStartExecuted").Tag("caller", e.CallerName).Tag("callee", e.FunctionName) if e.Err != nil { span.ErrVoid(e.Err) } else { span.Message("runtime:" + e.Runtime.String()) } case *fxevent.OnStopExecuting: - span.OverrideName(e.CallerName).Tag("callee", e.FunctionName) + span.OverrideName("OnStopExecuting").Tag("caller", e.CallerName).Tag("callee", e.FunctionName) case *fxevent.OnStopExecuted: - span.OverrideName(e.CallerName).Tag("callee", e.FunctionName) + span.OverrideName("OnStopExecuted").Tag("caller", e.CallerName).Tag("callee", e.FunctionName) if e.Err != nil { span.ErrVoid(e.Err) } else { @@ -45,9 +45,9 @@ func (t fxTracer) LogEvent(event fxevent.Event) { span.OverrideName("Provided"). Message("output types:" + strings.Join(e.OutputTypeNames, ",")).ErrVoid(e.Err) case *fxevent.Invoking: - span.OverrideName(e.FunctionName) + span.OverrideName("Invoking").Tag("func", e.FunctionName) case *fxevent.Invoked: - span.OverrideName(e.FunctionName) + span.OverrideName("Invoked").Tag("func", e.FunctionName) if e.Err != nil { span.ErrSpan(e.Err).Message("stack:" + e.Trace) } @@ -62,7 +62,7 @@ func (t fxTracer) LogEvent(event fxevent.Event) { case *fxevent.Started: span.OverrideName("Started").ErrVoid(e.Err) case *fxevent.LoggerInitialized: - span.OverrideName(e.ConstructorName).ErrVoid(e.Err) + span.OverrideName("LoggerInitialized").Tag("caller", e.ConstructorName).ErrVoid(e.Err) } } @@ -80,12 +80,15 @@ func Module(tf klogga.TracerProvider) fx.Option { // Full Set up the default logging for the app // registering logging and the klogga factory, -// that later can be reconfigured with more loggers +// that later can be reconfigured with more loggers via fx.Decorate func Full() fx.Option { tf := klogga.NewFactory(golog.New(nil)) return fx.Options( Module(tf), fx.Supply(tf), fx.Provide(func(tf *klogga.Factory) klogga.TracerProvider { return tf }), - ) + fx.Invoke(func(tf *klogga.Factory, lc fx.Lifecycle) error { + lc.Append(fx.Hook{OnStop: tf.Shutdown}) + return nil + })) } diff --git a/adapters/fx/runner.go b/adapters/fx/runner.go index 5e1db34..3c198e3 100644 --- a/adapters/fx/runner.go +++ b/adapters/fx/runner.go @@ -2,6 +2,7 @@ package fx import ( "context" + "errors" "fmt" "github.com/KasperskyLab/klogga" "go.uber.org/fx" @@ -56,20 +57,22 @@ func (rr RunnersGroup) RegisterWithErrors(tf klogga.TracerProvider, lc fx.Lifecy ctx, cancelFunc := context.WithCancel(context.Background()) lc.Append(ToHookWithCtx(runner, cancelFunc)) go func(r Runner) { + runnerName := reflect.TypeOf(r).String() select { case err := <-re.Error(): + if err == nil { + err = errors.New("") + } klogga.Message("runner error"). - Tag("runner", reflect.TypeOf(r).String()). - ErrSpan(err).FlushTo(trs) - case <-ctx.Done(): - - } - - if err := s.Shutdown(); err != nil { - klogga.Message("shutdowner error"). - Tag("runner", reflect.TypeOf(r).String()). + Tag("runner", runnerName). ErrSpan(err).FlushTo(trs) + if err := s.Shutdown(); err != nil { + klogga.Message("shutdowner error"). + Tag("runner", runnerName). + ErrSpan(err).FlushTo(trs) + } + case <-ctx.Done(): } }(runner) } @@ -86,9 +89,8 @@ func ToHookWithCtx(r Runner, onStopped context.CancelFunc) fx.Hook { return fx.Hook{ OnStart: r.Start, OnStop: func(ctx context.Context) error { - err := r.Stop(ctx) - onStopped() - return err + defer onStopped() + return r.Stop(ctx) }, } } diff --git a/adapters/grpc/grpc_adapter.go b/adapters/grpc/grpc_adapter.go index 4bfb188..77a4d6f 100644 --- a/adapters/grpc/grpc_adapter.go +++ b/adapters/grpc/grpc_adapter.go @@ -12,8 +12,6 @@ type LoggerV2 struct { } type Conf struct { - // 0 - log everything - // 4 - log nothing VerbosityLevel klogga.LogLevel } diff --git a/batcher/batcher.go b/batcher/batcher.go index e5dd11e..f3cdb12 100644 --- a/batcher/batcher.go +++ b/batcher/batcher.go @@ -44,10 +44,16 @@ func (c *Config) GetBufferSize() int { return c.GetBatchSize() * 5 } -func ConfigDefault() Config { +// ConfigDefault generates default batcher config +// non-nil optional config will be used instead +func ConfigDefault(cc ...*Config) Config { + if len(cc) > 0 && cc[0] != nil { + return *cc[0] + } return Config{ - BatchSize: 20, - Timeout: 2 * time.Second, + BatchSize: 512, + BufferSize: 2048, + Timeout: 5 * time.Second, } } @@ -132,8 +138,12 @@ func (b *Batcher) Write(ctx context.Context, spans []*klogga.Span) error { func (b *Batcher) Shutdown(ctx context.Context) (err error) { b.TriggerFlush() + if b.stop == nil { + return nil + } select { case b.stop <- struct{}{}: + b.stop = nil case <-ctx.Done(): err = ctx.Err() } diff --git a/batcher/batcher_test.go b/batcher/batcher_test.go index 3462a08..4f2e2ec 100644 --- a/batcher/batcher_test.go +++ b/batcher/batcher_test.go @@ -4,6 +4,7 @@ import ( "github.com/KasperskyLab/klogga" "github.com/KasperskyLab/klogga/util/testutil" "github.com/stretchr/testify/require" + "sync" "testing" "time" ) @@ -146,3 +147,41 @@ func TestWriteLotsOfSpans(t *testing.T) { time.Sleep(150 * time.Millisecond) require.True(t, len(tw.GetSpans()) >= 10) } + +func TestShutdownTwice(t *testing.T) { + tw := &exporterStub{} + rawTracer := New( + tw, Config{ + BatchSize: 1000, + Timeout: 100 * time.Millisecond, + }, + ) + tf := klogga.NewFactory(rawTracer) + + err := tf.Shutdown(testutil.Timeout()) + require.NoError(t, err) + err = tf.Shutdown(testutil.Timeout()) + require.NoError(t, err) +} + +func TestShutdownManyGoroutines(t *testing.T) { + tw := &exporterStub{} + rawTracer := New( + tw, Config{ + BatchSize: 1000, + Timeout: 100 * time.Millisecond, + }, + ) + tf := klogga.NewFactory(rawTracer) + + wg := sync.WaitGroup{} + for i := 0; i < 10; i++ { + go func() { + wg.Add(1) + defer wg.Done() + err := tf.Shutdown(testutil.Timeout()) + require.NoError(t, err) + }() + } + wg.Wait() +} diff --git a/examples/basic_app/main.go b/examples/basic_app/main.go index d9ad44f..76a5564 100644 --- a/examples/basic_app/main.go +++ b/examples/basic_app/main.go @@ -3,13 +3,13 @@ package main import ( "context" "github.com/KasperskyLab/klogga" - "github.com/KasperskyLab/klogga/exporters/golog" + "github.com/KasperskyLab/klogga/util" "time" ) func main() { // kreating a factory, with the simplest exporter - tf := klogga.NewFactory(golog.New(nil)) + tf := util.DefaultFactory() // kreating a tracer with a package name trs := tf.NamedPkg() @@ -26,5 +26,4 @@ func main() { span.Val("meaning", 42) // sleep a bit, to have us some non-zero duration time.Sleep(154 * time.Millisecond) - } diff --git a/examples/fx_app/main.go b/examples/fx_app/main.go new file mode 100644 index 0000000..830ad35 --- /dev/null +++ b/examples/fx_app/main.go @@ -0,0 +1,60 @@ +package main + +import ( + "context" + "github.com/KasperskyLab/klogga" + fxAdapter "github.com/KasperskyLab/klogga/adapters/fx" + "go.uber.org/fx" + "time" +) + +func main() { + fx.New(CreateApp()).Run() +} + +func CreateApp() fx.Option { + return fx.Options( + fx.Provide(NewRunner, + fx.Annotate(func(r *Runner) fxAdapter.Runner { return r }, fxAdapter.TagRunner...)), + fxAdapter.Full(), + fx.Invoke(fxAdapter.RegisterRunners), // register runnerA + ) +} + +type Runner struct { + trs klogga.Tracer + stop chan struct{} +} + +func NewRunner(trsFactory klogga.TracerProvider) *Runner { + return &Runner{ + trs: trsFactory.Named("runner_a"), + } +} + +func (r *Runner) Start(ctx context.Context) error { + span := klogga.StartLeaf(ctx) + defer r.trs.Finish(span) + + go func() { + for i := 0; ; i++ { + r.LogSomething(i) + select { + case <-r.stop: + return + case <-time.After(2 * time.Second): + } + } + }() + return nil +} + +func (*Runner) Stop(context.Context) error { + return nil +} + +func (r *Runner) LogSomething(iteration int) { + span := klogga.StartLeaf(context.Background(), klogga.WithName("run_func")) + defer r.trs.Finish(span) + span.Val("iteration", iteration) +} diff --git a/exporter.go b/exporter.go index 3b8c498..f20e2af 100644 --- a/exporter.go +++ b/exporter.go @@ -9,6 +9,9 @@ import ( // to be more generic accepts batches right away type Exporter interface { Write(ctx context.Context, spans []*Span) error + + // Shutdown is called to cleanup the exporter. Exporter cannot be used after that. + // Should be idempotent i.e. should work fine when called multiple times. Shutdown(ctx context.Context) error } diff --git a/exporters/otel/otel_exporter.go b/exporters/otel/otel_exporter.go index 6c6b933..3f32489 100644 --- a/exporters/otel/otel_exporter.go +++ b/exporters/otel/otel_exporter.go @@ -7,7 +7,6 @@ import ( "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/trace" - "time" ) // Exporter basic exporter of klogga spans to otel tracer @@ -38,7 +37,7 @@ func (t *Exporter) Write(ctx context.Context, spans []*klogga.Span) error { } _, otelSpan := t.tracer.Start( trace.ContextWithSpanContext(ctx, trace.NewSpanContext(config)), - span.Name(), + span.Component().String()+"/"+span.PackageClass()+"."+span.Name(), trace.WithTimestamp(span.StartedTs()), ) @@ -68,8 +67,7 @@ func (t *Exporter) Write(ctx context.Context, spans []*klogga.Span) error { // possibly should have something like this: // otelSpan.SetAttributes(attribute.String("klogga_id", span.ID().String())) - time.Sleep(500 * time.Millisecond) - otelSpan.End() + otelSpan.End(trace.WithTimestamp(span.FinishedTs())) } return nil } diff --git a/exporters/otel/readme.md b/exporters/otel/readme.md new file mode 100644 index 0000000..05367c9 --- /dev/null +++ b/exporters/otel/readme.md @@ -0,0 +1 @@ +Exporter [to opentelemetry go instrumentation](https://opentelemetry.io/docs/instrumentation/go/) \ No newline at end of file diff --git a/exporters/postgres/pg_exporter.go b/exporters/postgres/pg_exporter.go index 2e3c405..6af3967 100644 --- a/exporters/postgres/pg_exporter.go +++ b/exporters/postgres/pg_exporter.go @@ -24,15 +24,15 @@ const ( DefaultSchema = "audit" ErrorPostgresTable = DefaultSchema + "." + ErrorPostgresTableName - defaultWriteTimeout = time.Second - msgUnableToConnectPG = "unable to connect PG" - msgUnableToBeginTx = "unable to begin TX" - msgUnableToCommitTx = "unable to commit TX" - msgUnableToPrepareStatement = "unable to prepare statement" - msgUnableToExecStatement = "unable to exec statement" - msgUnableToQuery = "unable to query" - magUnableToScan = "unable to scan" - msgUnableToExec = "unable to exec" + defaultWriteTimeout = time.Second + + messageUnableToConnectPG = "unable to connect to postgres" + messageUnableToBeginTx = "unable to begin transaction" + messageUnableToCommitTx = "unable to commit transaction" + messageUnableToPrepare = "unable to prepare statement" + messageUnableToQuery = "unable to query" + messageUnableToScan = "unable to scan" + messageUnableToExec = "unable to exec" ) // Conf parameters on how klogga works with DB @@ -71,7 +71,7 @@ type Exporter struct { // New to be used with batcher // cfg - config // connFactory - connection to PG -// trs - a tracer to write pg_exporter logs, like DB changes, pass nil to setup default golog tracer +// trs - a tracer to write pg_exporter logs, like DB changes, pass nil to set default golog tracer func New(cfg *Conf, connFactory Connector, trs klogga.Tracer) *Exporter { if trs == nil { trs = klogga.NewFactory(golog.New(nil)).NamedPkg() @@ -167,8 +167,11 @@ func (e *Exporter) Write(ctx context.Context, spans []*klogga.Span) error { }, ) - recordSets, errSpans := e.createRecordSets(spans...) - e.writeErrSpans(ctx, errSpans) + recordSets, errDescriptors := e.createRecordSets(spans...) + for i := 0; i < len(errDescriptors); i++ { + e.writeErr(ctx, errDescriptors[i].Span) + } + for tableName, recordSet := range recordSets { if !e.cfg.SkipSchemaCreation { err := e.updateSchema(ctx, tableName, recordSet) @@ -203,7 +206,9 @@ func (e *Exporter) updateSchema(ctx context.Context, tableName string, dataset R } else { alterSchema, failures := schema.GetAlterSchema(dataset) if len(failures) > 0 { - e.writeErrSpans(ctx, failures) + for i := 0; i < len(failures); i++ { + e.writeErr(ctx, failures[i].Span) + } return span.Err( errors.Errorf( "alter table failed (%v failures), first failure: %v", len(failures), failures[0].Err(), @@ -232,7 +237,7 @@ func (e *Exporter) writeRecordSet(ctx context.Context, tableName string, recordS conn, err := e.connFactory.GetConnection(ctx) if err != nil { - span.ErrVoid(errors.Wrap(err, msgUnableToConnectPG)) + span.ErrVoid(errors.Wrap(err, messageUnableToConnectPG)) return } defer func() { span.DeferErr(conn.Close()) }() @@ -240,7 +245,7 @@ func (e *Exporter) writeRecordSet(ctx context.Context, tableName string, recordS isCommitted := false tx, err := conn.BeginTx(ctx, nil) if err != nil { - span.ErrVoid(errors.Wrap(err, msgUnableToBeginTx)) + span.ErrVoid(errors.Wrap(err, messageUnableToBeginTx)) return } defer func() { @@ -254,7 +259,7 @@ func (e *Exporter) writeRecordSet(ctx context.Context, tableName string, recordS span.Val("columns_count", recordSet.Schema.ColumnsCount()) stmt, err := tx.Prepare(query) if err != nil { - span.ErrVoid(errors.Wrap(err, msgUnableToPrepareStatement)) + span.ErrVoid(errors.Wrap(err, messageUnableToPrepare)) return } defer func() { @@ -271,8 +276,8 @@ func (e *Exporter) writeRecordSet(ctx context.Context, tableName string, recordS strWarn = sErr.Error() } - vv := []interface{}{ - span.StartedTs(), + vv := []any{ + span.StartedTs().UTC(), span.ID().Bytes(), span.TraceID().AsUUID(), span.Host(), @@ -295,7 +300,7 @@ func (e *Exporter) writeRecordSet(ctx context.Context, tableName string, recordS } if _, err := stmt.ExecContext(ctx, vv...); err != nil { - span.ErrVoid(errors.Wrap(err, msgUnableToExecStatement)) + span.ErrVoid(errors.Wrap(err, messageUnableToExec)) continue } } @@ -306,7 +311,7 @@ func (e *Exporter) writeRecordSet(ctx context.Context, tableName string, recordS } if err := tx.Commit(); err != nil { - span.ErrVoid(errors.Wrap(err, msgUnableToCommitTx)) + span.ErrVoid(errors.Wrap(err, messageUnableToCommitTx)) } isCommitted = true } @@ -324,12 +329,12 @@ func (e *Exporter) createTable(ctx context.Context, tableName string, schema *Ta conn, err := e.connFactory.GetConnection(ctx) if err != nil { - return span.Err(errors.Wrap(err, msgUnableToConnectPG)) + return span.Err(errors.Wrap(err, messageUnableToConnectPG)) } defer func() { span.DeferErr(conn.Close()) }() if _, err := conn.ExecContext(ctx, q); err != nil { span.Val(vals.Query, q) - return span.Err(errors.Wrap(err, msgUnableToExec)) + return span.Err(errors.Wrap(err, messageUnableToExec)) } return nil } @@ -349,11 +354,11 @@ func (e *Exporter) alterTable(ctx context.Context, tableName string, schema *Tab conn, err := e.connFactory.GetConnection(ctx) if err != nil { - return span.Err(errors.Wrap(err, msgUnableToConnectPG)) + return span.Err(errors.Wrap(err, messageUnableToConnectPG)) } defer func() { span.DeferErr(conn.Close()) }() if _, err := conn.ExecContext(ctx, q); err != nil { - return span.Err(errors.Wrap(err, msgUnableToExec)) + return span.Err(errors.Wrap(err, messageUnableToExec)) } return nil } @@ -367,7 +372,7 @@ func (e *Exporter) loadSchemas(ctx context.Context) error { defer cancel() conn, err := e.connFactory.GetConnection(ctx) if err != nil { - return span.Err(errors.Wrap(err, msgUnableToConnectPG)) + return span.Err(errors.Wrap(err, messageUnableToConnectPG)) } defer func() { span.DeferErr(conn.Close()) }() @@ -380,10 +385,10 @@ func (e *Exporter) loadSchemas(ctx context.Context) error { rows, err := conn.QueryContext(ctx, query, args...) if err != nil { - return span.Err(errors.Wrap(err, msgUnableToQuery)) + return span.Err(errors.Wrap(err, messageUnableToQuery)) } if err := rows.Err(); err != nil { - return span.Err(errors.Wrap(err, msgUnableToQuery)) + return span.Err(errors.Wrap(err, messageUnableToQuery)) } defer func() { span.DeferErr(rows.Close()) @@ -394,7 +399,7 @@ func (e *Exporter) loadSchemas(ctx context.Context) error { var tableName string var colSchema ColumnSchema if err := rows.Scan(&tableName, &colSchema.Name, &colSchema.DataType); err != nil { - return span.Err(errors.Wrap(err, magUnableToScan)) + return span.Err(errors.Wrap(err, messageUnableToScan)) } if _, found := tables[tableName]; !found { tables[tableName] = NewTableSchema([]*ColumnSchema{}) @@ -419,47 +424,45 @@ func (e *Exporter) loadSchemas(ctx context.Context) error { return nil } -func (e *Exporter) writeErrSpans(ctx context.Context, errDescrs []ErrDescriptor) { - if len(errDescrs) == 0 { - return - } +func (e *Exporter) writeErr(ctx context.Context, errSpan *klogga.Span) { span, ctx := klogga.Start(ctx) defer e.writeIfErr(span) - span.Val(vals.Count, len(errDescrs)) conn, err := e.connFactory.GetConnection(ctx) if err != nil { - span.ErrVoid(errors.Wrap(err, msgUnableToConnectPG)) + span.ErrVoid(errors.Wrap(err, messageUnableToConnectPG)) return } defer func() { span.DeferErr(conn.Close()) }() statementText := e.errTable.InsertStatement(e.cfg.SchemaName, ErrorPostgresTableName) - for i := 0; i < len(errDescrs); i++ { - errDescr := errDescrs[i] - warn := "" - if errDescr.Warn() != nil { - warn = errDescr.Warn().Error() - } - _, err := conn.ExecContext( - ctx, - statementText, - errDescr.Span.StartedTs(), - errDescr.Span.ID().Bytes(), - errDescr.Span.TraceID().AsUUID(), - errDescr.Span.Host(), - errDescr.Span.PackageClass(), - errDescr.Span.Name(), - errDescr.Span.ParentID().AsNullableBytes(), - errDescr.Err().Error(), - warn, - errDescr.Span.Duration(), - errDescr.Span.Component(), - ) - if err != nil { - span.Val(vals.Query, statementText).ErrVoid(errors.Wrap(err, "unable to write bad span")) - } + warnText := "" + if errSpan.HasWarn() { + warnText = errSpan.Warns().Error() + } + errText := "" + if errSpan.HasErr() { + errText = errSpan.Errs().Error() + } + + _, err = conn.ExecContext( + ctx, + statementText, + errSpan.StartedTs().UTC(), + errSpan.ID().Bytes(), + errSpan.TraceID().AsUUID(), + errSpan.Host(), + errSpan.PackageClass(), + errSpan.Name(), + errSpan.ParentID().AsNullableBytes(), + errText, + warnText, + errSpan.Duration(), + errSpan.Component(), + ) + if err != nil { + span.Val(vals.Query, statementText).ErrVoid(errors.Wrap(err, "unable to write bad span")) } } @@ -488,18 +491,18 @@ func (e *Exporter) createRecordSets(spans ...*klogga.Span) (map[string]RecordSet for name, val := range e.getSpanVals(span) { name = toPgColumnName(name) - col, found := dataset.Schema.Column(name) + existingCol, found := dataset.Schema.Column(name) valType, _ := GetPgTypeVal(val) - newColumn := ColumnSchema{ + newCol := ColumnSchema{ Name: name, DataType: valType, } if !found { - dataset.Schema.AddColumn(newColumn) + dataset.Schema.AddColumn(newCol) continue } - if !strings.EqualFold(newColumn.DataType, col.DataType) { - errSpans = append(errSpans, newErrDescriptor(tableName, span, newColumn, *col)) + if existingCol.DataType != valType { + errSpans = append(errSpans, newErrDescriptor("", span, newCol, *existingCol)) } } @@ -545,5 +548,6 @@ func (e *Exporter) getSpanVals(span *klogga.Span) map[string]interface{} { func (e *Exporter) writeIfErr(span *klogga.Span) { if span.HasErr() { span.FlushTo(e.trs) + e.writeErr(context.Background(), span) } } diff --git a/exporters/postgres/pg_exporter_test.go b/exporters/postgres/pg_exporter_test.go index 3301cbe..84f7b63 100644 --- a/exporters/postgres/pg_exporter_test.go +++ b/exporters/postgres/pg_exporter_test.go @@ -93,3 +93,38 @@ func TestPgValueJsonEmpty(t *testing.T) { require.Equal(t, PgJsonbTypeName, pgt) require.Equal(t, "null", v) } + +type StringBased string + +func TestPgValueStringBased(t *testing.T) { + vv := "lalala" + pgt, v := GetPgTypeVal(StringBased(vv)) + require.Equal(t, PgTextTypeName, pgt) + require.Equal(t, v, vv) +} + +type structType struct { + V1 int + V2 int +} + +func TestStructType(t *testing.T) { + pgt, _ := GetPgTypeVal(structType{ + V1: 11, + V2: 12, + }) + require.Equal(t, PgJsonbTypeName, pgt) +} + +func TestStructPointerType(t *testing.T) { + pgt, _ := GetPgTypeVal(&structType{ + V1: 11, + V2: 12, + }) + require.Equal(t, PgJsonbTypeName, pgt) +} + +func TestArrayType(t *testing.T) { + pgt, _ := GetPgTypeVal([]int{2, 3, 4}) + require.Equal(t, PgJsonbTypeName, pgt) +} diff --git a/exporters/postgres/pgconnector/pg_example_test.go b/exporters/postgres/pgconnector/pg_example_test.go index faf8e17..f70afba 100644 --- a/exporters/postgres/pgconnector/pg_example_test.go +++ b/exporters/postgres/pgconnector/pg_example_test.go @@ -22,6 +22,10 @@ func TestConnectPg(t *testing.T) { _, err = rawConn.Exec("create schema if not exists audit") require.NoError(t, err) + // truncate audit.example_test table to ensure clean test + _, err = rawConn.Exec("TRUNCATE audit.example_test") + require.NoError(t, err) + // postgres exporter needs a separate tracer, to write its own errors // this tracer shod use some simpler exporter, like golog, anything closer than external database // be careful not to recurse that ) diff --git a/exporters/postgres/postgres_types.go b/exporters/postgres/postgres_types.go index 62fed95..eee64bf 100644 --- a/exporters/postgres/postgres_types.go +++ b/exporters/postgres/postgres_types.go @@ -42,17 +42,27 @@ func GetPgTypeVal(a interface{}) (string, interface{}) { case fmt.Stringer: return PgTextTypeName, v.String() default: - if v != reflect.Struct { + t := reflect.TypeOf(v) + if isJsonDesired(t) || t.Kind() == reflect.Pointer && isJsonDesired(t.Elem()) { data, err := json.Marshal(v) - if err != nil { - return PgTextTypeName, fmt.Sprintf("%v", v) + if err == nil { + return PgJsonbTypeName, data } - return PgJsonbTypeName, data } return PgTextTypeName, fmt.Sprintf("%v", v) } } +func isJsonDesired(t reflect.Type) bool { + if t == nil { + return false + } + return t.Kind() == reflect.Struct || + t.Kind() == reflect.Slice || + t.Kind() == reflect.Map || + t.Kind() == reflect.Array +} + // finds column value by name in tags of vals of the span func findColumnValue(span *klogga.Span, name string) interface{} { val, found := span.Tags()[name] @@ -75,12 +85,14 @@ type ErrDescriptor struct { } func newErrDescriptor(table string, span *klogga.Span, col, existingCol ColumnSchema) ErrDescriptor { - return ErrDescriptor{ + descriptor := ErrDescriptor{ Table: table, Span: span, Column: col, ExistingColumn: existingCol, } + span.ErrVoid(descriptor.Err()) + return descriptor } func (e *ErrDescriptor) Err() error { diff --git a/exporters/postgres/table_schema.go b/exporters/postgres/table_schema.go index e42c5b3..79df15f 100644 --- a/exporters/postgres/table_schema.go +++ b/exporters/postgres/table_schema.go @@ -26,17 +26,17 @@ func NewTableSchema(columns []*ColumnSchema) *TableSchema { } } -func (t TableSchema) ColumnsCount() int { +func (t *TableSchema) ColumnsCount() int { return len(t.columns) } -func (t TableSchema) ColumnNames() []string { +func (t *TableSchema) ColumnNames() []string { return t.columnsNames } // GetAlterSchema returns missing columns' schema // returns spans that cannot be written just by adding columns -func (t TableSchema) GetAlterSchema(dataset RecordSet) (*TableSchema, []ErrDescriptor) { +func (t *TableSchema) GetAlterSchema(dataset RecordSet) (*TableSchema, []ErrDescriptor) { alterSchema := NewTableSchema([]*ColumnSchema{}) errDescriptors := make([]ErrDescriptor, 0) @@ -72,7 +72,7 @@ func (t *TableSchema) Merge(newCols []*ColumnSchema) *TableSchema { return tCopy } -func (t TableSchema) Column(name string) (*ColumnSchema, bool) { +func (t *TableSchema) Column(name string) (*ColumnSchema, bool) { col, ok := t.mm[name] return col, ok } @@ -85,12 +85,12 @@ func (t *TableSchema) AddColumn(col ColumnSchema) { t.mm[col.Name] = &col } -func (t TableSchema) Columns() []*ColumnSchema { +func (t *TableSchema) Columns() []*ColumnSchema { return t.columns } // InsertStatement NOT injection safe -func (t TableSchema) InsertStatement(schema string, tableName string) string { +func (t *TableSchema) InsertStatement(schema string, tableName string) string { paramsStr := "$1" for i := 2; i <= t.ColumnsCount(); i++ { paramsStr += fmt.Sprintf(",$%v", i) @@ -104,7 +104,7 @@ func (t TableSchema) InsertStatement(schema string, tableName string) string { } // CreateTableStatement NOT injection safe -func (t TableSchema) CreateTableStatement(schema, tableName string, timeCol *ColumnSchema, useTimescale bool) string { +func (t *TableSchema) CreateTableStatement(schema, tableName string, timeCol *ColumnSchema, useTimescale bool) string { b := strings.Builder{} b.WriteString(fmt.Sprintf("CREATE TABLE %s.%s\n", schema, tableName)) @@ -126,7 +126,7 @@ func (t TableSchema) CreateTableStatement(schema, tableName string, timeCol *Col } // AlterTableStatement NOT injection safe -func (t TableSchema) AlterTableStatement(schema, tableName string) string { +func (t *TableSchema) AlterTableStatement(schema, tableName string) string { b := strings.Builder{} b.WriteString(fmt.Sprintf("ALTER TABLE %v.%v\n", schema, tableName)) @@ -152,7 +152,7 @@ type ColumnSchema struct { IsNullable bool } -func (s ColumnSchema) SQL() string { +func (s *ColumnSchema) SQL() string { nullableStr := "null" if !s.IsNullable { nullableStr = "not " + nullableStr diff --git a/exporters/readme.md b/exporters/readme.md new file mode 100644 index 0000000..c3bc6f5 --- /dev/null +++ b/exporters/readme.md @@ -0,0 +1 @@ +This directory contains klogga exporters. \ No newline at end of file diff --git a/factory.go b/factory.go index 700a91a..ae27591 100644 --- a/factory.go +++ b/factory.go @@ -35,7 +35,7 @@ func (tf *Factory) Named(componentName ComponentName) Tracer { // NamedPkg creates a named tracer with the name as package name, where this constructor is called func (tf *Factory) NamedPkg() Tracer { - p, _, _ := reflectutil.GetPackageClassFunc() + p, _, _ := reflectutil.GetPackageClassFunc(2) return tf.Named(ComponentName(p)) } @@ -52,6 +52,12 @@ func (tf *Factory) AddExporter(exporter Exporter) *Factory { return tf } +// RemoveAllExporters clear exporters list, nothing will be exported +func (tf *Factory) RemoveAllExporters() *Factory { + tf.exporters = []Exporter{} + return tf +} + func (tf *Factory) write(ctx context.Context, spans []*Span) error { return tf.exporters.Write(ctx, spans) } diff --git a/go.mod b/go.mod index 92e2c07..57b2bd9 100644 --- a/go.mod +++ b/go.mod @@ -1,32 +1,49 @@ module github.com/KasperskyLab/klogga -go 1.16 +go 1.18 require ( - github.com/Masterminds/squirrel v1.5.2 + github.com/Masterminds/squirrel v1.5.3 github.com/golang/mock v1.6.0 github.com/google/uuid v1.3.0 github.com/hashicorp/go-multierror v1.1.1 + github.com/hashicorp/go-version v1.6.0 github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab - github.com/jmoiron/sqlx v1.3.4 + github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.4 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.1 - github.com/stretchr/testify v1.7.0 - go.opentelemetry.io/otel v1.3.0 - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.3.0 - go.opentelemetry.io/otel/sdk v1.3.0 - go.opentelemetry.io/otel/trace v1.3.0 - go.uber.org/atomic v1.9.0 - go.uber.org/fx v1.16.0 + github.com/stretchr/testify v1.8.0 + go.opentelemetry.io/otel v1.10.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.10.0 + go.opentelemetry.io/otel/sdk v1.10.0 + go.opentelemetry.io/otel/trace v1.10.0 + go.uber.org/atomic v1.10.0 + go.uber.org/fx v1.18.1 ) require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/kr/text v0.2.0 // indirect + github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect + github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect - go.uber.org/dig v1.13.0 // indirect - go.uber.org/multierr v1.7.0 // indirect - go.uber.org/zap v1.20.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.32.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect + go.uber.org/dig v1.15.0 // indirect + go.uber.org/multierr v1.8.0 // indirect + go.uber.org/zap v1.23.0 // indirect + golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect + google.golang.org/protobuf v1.26.0 // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index daf390e..e347a3f 100644 --- a/go.sum +++ b/go.sum @@ -33,16 +33,14 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Masterminds/squirrel v1.5.2 h1:UiOEi2ZX4RCSkpiNDQN5kro/XIBpSRk9iTqdIRPzUXE= -github.com/Masterminds/squirrel v1.5.2/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= +github.com/Masterminds/squirrel v1.5.3 h1:YPpoceAcxuzIljlr5iWpNKaql7hLeG1KLSrhvdHpkZc= +github.com/Masterminds/squirrel v1.5.3/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= -github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -73,13 +71,13 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.1 h1:DX7uPQ4WgAWfoh+NGGlbJQswnYIVvz0SRlLS3rPZQDA= -github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/stdr v1.2.0 h1:j4LrlVXgrbIWO83mmQUnK0Hi+YnbD+vzrE1z/EphbFE= -github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI= -github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -123,8 +121,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -145,13 +142,15 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab h1:HqW4xhhynfjrtEiiSGcQUd6vrK23iMam1FO8rI7mwig= github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w= -github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= +github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= +github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -224,11 +223,14 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -238,33 +240,26 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/otel v1.3.0 h1:APxLf0eiBwLl+SOXiJJCVYzA1OOJNyAoV8C5RNRyy7Y= -go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.3.0 h1:Kte45gGM12Ks0pZng7Pi+IFlbbeY287ZpGX0s0G9al8= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.3.0/go.mod h1:PQLM+xJ3EMSZU9rMevmw+4nH1efyp23CW/nD9BlB3sg= -go.opentelemetry.io/otel/sdk v1.3.0 h1:3278edCoH89MEJ0Ky8WQXVmDQv3FX4ZJ3Pp+9fJreAI= -go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs= -go.opentelemetry.io/otel/trace v1.3.0 h1:doy8Hzb1RJ+I3yFhtDmwNc7tIyw1tNMOIsyPzp1NOGY= -go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.opentelemetry.io/otel v1.10.0 h1:Y7DTJMR6zs1xkS/upamJYk0SxxN4C9AqRd77jmZnyY4= +go.opentelemetry.io/otel v1.10.0/go.mod h1:NbvWjCthWHKBEUMpf0/v8ZRZlni86PpGFEMA9pnQSnQ= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.10.0 h1:c9UtMu/qnbLlVwTwt+ABrURrioEruapIslTDYZHJe2w= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.10.0/go.mod h1:h3Lrh9t3Dnqp3NPwAZx7i37UFX7xrfnO1D+fuClREOA= +go.opentelemetry.io/otel/sdk v1.10.0 h1:jZ6K7sVn04kk/3DNUdJ4mqRlGDiXAVuIG+MMENpTNdY= +go.opentelemetry.io/otel/sdk v1.10.0/go.mod h1:vO06iKzD5baltJz1zarxMCNHFpUlUiOy4s65ECtn6kE= +go.opentelemetry.io/otel/trace v1.10.0 h1:npQMbR8o7mum8uF95yFbOEJffhs1sbCOfDh8zAJiH5E= +go.opentelemetry.io/otel/trace v1.10.0/go.mod h1:Sij3YYczqAdz+EhmGhE6TpTxUO5/F/AzrK+kxfGqySM= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/dig v1.12.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= -go.uber.org/dig v1.13.0 h1:bb9lVW3gtpQsNb07d0xL5vFwsjHidPJxaR/zSsbmfVQ= -go.uber.org/dig v1.13.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= -go.uber.org/fx v1.16.0 h1:N8i80+X1DCX+qMRiKzM+jPPZiIiyK/bVCysga3+B+1w= -go.uber.org/fx v1.16.0/go.mod h1:OMoT5BnXcOaiexlpjtpE4vcAmzyDKyRs9TRYXCzamx8= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/dig v1.15.0 h1:vq3YWr8zRj1eFGC7Gvf907hE0eRjPTZ1d3xHadD6liE= +go.uber.org/dig v1.15.0/go.mod h1:pKHs0wMynzL6brANhB2hLMro+zalv1osARTviTcqHLM= +go.uber.org/fx v1.18.1 h1:I7VWkdv4iKcbpH7KVSi9Fe1LGmpJv+pbBIb9NidPb+E= +go.uber.org/fx v1.18.1/go.mod h1:g0V1KMQ66zIRk8bLu3Ea5Jt2w/cHlOIp4wdRsgh0JaY= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= -go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -go.uber.org/zap v1.20.0 h1:N4oPlghZwYG55MlU6LXk/Zp00FVNE9X9wrYO8CEs4lc= -go.uber.org/zap v1.20.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= +go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -292,7 +287,6 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -384,10 +378,8 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -415,9 +407,6 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191030062658-86caa796c7ab/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -444,12 +433,9 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -538,13 +524,12 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/legal_notices.txt b/legal_notices.txt index 06fcd44..301e002 100644 --- a/legal_notices.txt +++ b/legal_notices.txt @@ -3,156 +3,141 @@ ------- This file contains information about dependencies which are used in the Klogga. - -atomic v1.9.0 -Copyright (c) 2016 Uber Technologies, Inc. +squirrel 1.5.3 +Copyright (C) 2014-2015, Lann Martin +Copyright (C) 2015-2016, Google +Copyright (C) 2015, Matt Farina and Matt Butcher ----- -Distributed under the terms of the MIT License (MIT) +Distributed under the terms of the MIT License ----- -dig v1.13.0 -Copyright (c) 2017-2018 Uber Technologies, Inc. +influxdata/influxdb1-client Commit b269163 +Copyright (c) 2019 InfluxData ----- -Distributed under the terms of the MIT License (MIT) +Distributed under the terms of the MIT License ----- -fx v1.16.0 -Copyright (c) 2016-2018 Uber Technologies, Inc. +sqlx 1.3.5 +Copyright (c) 2013, Jason Moiron ----- -Distributed under the terms of the MIT License (MIT) +Distributed under the terms of the MIT License ----- -influxdb1-client v0.0.0-20200827194710-b269163b24ab -Copyright (c) 2019 InfluxData +lib/pq 1.10.4 +Copyright (c) 2011-2013, 'pq' Contributors Portions Copyright (C) 2011 Blake Mizerany ----- -Distributed under the terms of the MIT License (MIT) +Distributed under the terms of the MIT License ----- -multierr v1.7.0 -Copyright (c) 2017-2021 Uber Technologies, Inc. +stretchr/testify 1.8.0 +Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. ----- -Distributed under the terms of the MIT License (MIT) +Distributed under the terms of the MIT License ----- -pq v1.10.4 -Copyright (c) 2011-2013, 'pq' Contributors -Portions Copyright (C) 2011 Blake Mizerany +go.uber.org/atomic 1.10.0 +Copyright (c) 2016 Uber Technologies, Inc. ----- -Distributed under the terms of the MIT License (MIT) +Distributed under the terms of the MIT License ----- -pretty v0.0.0-20200227124842-a10e7caefd8e -Copyright 2012 Keith Rarick +go.uber.org/fx 1.18.1 +Copyright (c) 2016-2018 Uber Technologies, Inc. ----- -Distributed under the terms of the MIT License (MIT) +Distributed under the terms of the MIT License ----- -sqlx v1.3.4 -Copyright (c) 2013, Jason Moiron +perks 1.0.1 +Copyright (C) 2013 Blake Mizerany ----- -Distributed under the terms of the MIT License (MIT) +Distributed under the terms of the MIT License ----- -squirrel v1.5.2 -Copyright (C) 2014-2015, Lann Martin -Copyright (C) 2015-2016, Google -Copyright (C) 2015, Matt Farina and Matt Butcher +github.com/cespare/xxhash/v2 2.1.2 +Copyright (c) 2016 Caleb Spare ----- -Distributed under the terms of the MIT License (MIT) +Distributed under the terms of the MIT License ----- -testify v1.7.0 -Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. +kr/text 0.2.0 +Copyright 2012 Keith Rarick ----- -Distributed under the terms of the MIT License (MIT) +Distributed under the terms of the MIT License ----- -text v0.2.0 -Copyright 2012 Keith Rarick +lann/builder Commit 47ae307 +Copyright (c) 2014-2015 Lann Martin ----- -Distributed under the terms of the MIT License (MIT) +Distributed under the terms of the MIT License ----- -zap v1.20.0 -Copyright (c) 2016-2017 Uber Technologies, Inc. +lann/ps Commit 62de8c4 +Copyright (c) 2013 Michael Hendricks ----- -Distributed under the terms of the MIT License (MIT) +Distributed under the terms of the MIT License ----- -== -the MIT License -== -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. - - -check.v1 v1.0.0-20200227125254-8fa46927fb4f -Copyright (c) 2010-2013 Gustavo Niemeyer . +niemeyer/pretty Commit a10e7ca +Copyright 2012 Keith Rarick ----- -Distributed under the terms of the BSD License (two-clause) +Distributed under the terms of the MIT License ----- -This library contains Benchmark.go distributed under the following terms: -Copyright (c) 2012 The Go Authors. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -* Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -errors v0.9.1 -Copyright (c) 2015, Dave Cheney +go.uber.org/dig 1.15.0 +Copyright (c) 2017-2018 Uber Technologies, Inc. ----- -Distributed under the terms of the BSD License (two-clause) +Distributed under the terms of the MIT License ----- -== -The BSD License (two-clause) -== -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +go.uber.org/multierr 1.8.0 +Copyright (c) 2017-2021 Uber Technologies, Inc. +----- +Distributed under the terms of the MIT License +----- -uuid v1.3.0 -Copyright (c) 2009,2014 Google Inc. All rights reserved. +go.uber.org/zap 1.23.0 +Copyright (c) 2016-2017 Uber Technologies, Inc. ----- -Distributed under the terms of the BSD License (three-clause) +Distributed under the terms of the MIT License ----- == -the BSD License (three-clause) +the MIT License == -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +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. + +golang/mock 1.6.0 +Copyright 2019 Google LLC +----- +Distributed under the terms of the Apache License Version 2.0 +----- -client_golang v1.12.1 -Prometheus instrumentation library for Go applications +prometheus/client_golang 1.12.1 Copyright 2012-2015 The Prometheus Authors ----- Distributed under the terms of the Apache License Version 2.0 ----- -This product includes software developed at SoundCloud Ltd. (http://soundcloud.com/). +This product includes software developed at +SoundCloud Ltd. (http://soundcloud.com/). The following components are included in this product: @@ -171,47 +156,78 @@ https://github.com/matttproud/golang_protobuf_extensions Copyright 2013 Matt T. Proud Licensed under the Apache License, Version 2.0 +go.opentelemetry.io/otel 1.10.0 +Copyright The OpenTelemetry Authors +----- +Distributed under the terms of the Apache License Version 2.0 +----- -mock v1.6.0 -Alex Reece -Google Inc. +go.opentelemetry.io/otel/exporters/stdout/stdouttrace 1.10.0 +Copyright The OpenTelemetry Authors ----- Distributed under the terms of the Apache License Version 2.0 ----- -otel v1.3.0 +go.opentelemetry.io/otel/sdk 1.10.0 Copyright The OpenTelemetry Authors ----- Distributed under the terms of the Apache License Version 2.0 ----- -sdk v1.3.0 +go.opentelemetry.io/otel/trace 1.10.0 Copyright The OpenTelemetry Authors ----- Distributed under the terms of the Apache License Version 2.0 ----- -stdouttrace v1.3.0 -Copyright The OpenTelemetry Authors +go-logr/logr 1.2.3 +Copyright 2019 The logr Authors. ----- Distributed under the terms of the Apache License Version 2.0 ----- -trace v1.3.0 -Copyright The OpenTelemetry Authors +go-logr/stdr 1.2.2 +Copyright 2019 The logr Authors. +----- +Distributed under the terms of the Apache License Version 2.0 +----- + + +golang_protobuf_extensions 1.0.1 +Copyright 2012 Matt T. Proud (matt.proud@gmail.com) +----- +Distributed under the terms of the Apache License Version 2.0 +----- + + +prometheus/client_model 0.2.0 +Copyright 2012-2015 The Prometheus Authors +----- +Distributed under the terms of the Apache License Version 2.0 +----- + + +github.com/prometheus/common 0.32.1 +Copyright 2015 The Prometheus Authors +----- +Distributed under the terms of the Apache License Version 2.0 +----- +This product includes software developed at +SoundCloud Ltd. (http://soundcloud.com/). + + +prometheus/procfs 0.7.3 +Copyright 2014-2015 The Prometheus Authors ----- Distributed under the terms of the Apache License Version 2.0 ----- -== -the Apache License Version 2.0 -== Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -240,25 +256,116 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS + +github.com/google/uuid 1.3.0 +Copyright (c) 2009,2014 Google Inc. All rights reserved. +----- +Distributed under the terms of the BSD License (three-clause) +----- + + +golang/protobuf 1.5.2 +Copyright 2019 The Go Authors + +----- +Distributed under the terms of the BSD License (three-clause) ----- -errwrap v1.1.0 -https://github.com/hashicorp/errwrap/tree/v1.1.0 +github.com/pmezard/go-difflib 1.0.0 +Copyright (c) 2013, Patrick Mezard +All rights reserved. ----- -Distributed under the terms of the Mozilla Public License, version 2.0 +Distributed under the terms of the BSD License (three-clause) ----- -go-multierror v1.1.1 -https://github.com/hashicorp/go-multierror/tree/v1.1.1 +golang.org/x/sys commit da31bd327af9 +Copyright (c) 2009 The Go Authors. All rights reserved. +----- +Distributed under the terms of the BSD License (three-clause) ----- -Distributed under the terms of the Mozilla Public License, version 2.0 +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. + +google.golang.org/protobuf 1.26.0 +Copyright (c) 2018 The Go Authors. All rights reserved. ----- +Distributed under the terms of the BSD License (three-clause) +----- +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. == -the Mozilla Public License, version 2.0 +the BSD License (three-clause) == +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +hashicorp/go-multierror 1.1.1 +https://github.com/hashicorp/go-multierror +----- +Distributed under the terms of the Mozilla Public License 2.0 +----- + + +go-version 1.6.0 +https://github.com/hashicorp/go-version +----- +Distributed under the terms of the Mozilla Public License 2.0 +----- + + +hashicorp/errwrap v1.1.0 +https://github.com/hashicorp/errwrap +----- +Distributed under the terms of the Mozilla Public License 2.0 +----- + + Mozilla Public License, version 2.0 1. Definitions 1.1. “Contributor” means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. @@ -341,4 +448,86 @@ This Source Code Form is subject to the terms of the Mozilla Public License, v. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - “Incompatible With Secondary Licenses” Notice -This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0. \ No newline at end of file +This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0. + +pkg/errors 0.9.1 +Copyright (c) 2015, Dave Cheney +All rights reserved. +----- +Distributed under the terms of the BSD License (two-clause) +----- + + +gopkg.in/check.v1 commit 8fa46927fb4f +Copyright (c) 2010-2013 Gustavo Niemeyer +All rights reserved. +----- +Distributed under the terms of the BSD License (two-clause) +----- + + +The BSD 2-Clause License +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +davecgh/go-spew 1.1.1 +Copyright (c) 2012-2016 Dave Collins +----- +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +----- + + +yaml 3.0.1 +This project is covered by two different licenses: MIT and Apache. + +#### MIT License #### + +The following files were ported to Go from C files of libyaml, and thus +are still covered by their original MIT license, with the additional +copyright staring in 2011 when the project was ported over: + + apic.go emitterc.go parserc.go readerc.go scannerc.go + writerc.go yamlh.go yamlprivateh.go + +Copyright (c) 2006-2010 Kirill Simonov +Copyright (c) 2006-2011 Kirill Simonov + +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. + +### Apache License ### + +All the remaining project files are covered by the Apache license: + +Copyright (c) 2011-2019 Canonical Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +----- \ No newline at end of file diff --git a/log_levels.go b/log_levels.go index 79d0307..6187cc7 100644 --- a/log_levels.go +++ b/log_levels.go @@ -5,6 +5,8 @@ type LogLevel int func (l LogLevel) String() string { switch l { + case Debug: + return "D" case Info: return "I" case Warn: @@ -19,6 +21,7 @@ func (l LogLevel) String() string { } const ( + Debug LogLevel = -1 Info LogLevel = 0 Warn LogLevel = 1 Error LogLevel = 2 diff --git a/span.go b/span.go index 53e7731..a863a5f 100644 --- a/span.go +++ b/span.go @@ -47,15 +47,34 @@ type Span struct { } // Start preferred way to start a new span, automatically sets basic span fields like class, name, host -func Start(ctx1 context.Context, opts ...SpanOption) (span *Span, ctx context.Context) { +func Start(ctx context.Context, opts ...SpanOption) (*Span, context.Context) { + return startInternal(ctx, opts...) +} + +// StartLeaf start new span without returning resulting context i.e. no child spans possibility +func StartLeaf(ctx context.Context, opts ...SpanOption) *Span { + span, _ := startInternal(ctx, opts...) + return span +} + +// Message is the simplest way to start a span, in the shortest way possible +// it doesn't use context, and doesn't return one. +// It is strongly discouraged to use Message unless for testing or showing off purposes. +func Message(message string, opts ...SpanOption) *Span { + span, _ := startInternal(context.Background(), opts...) + span.Message(message) + return span +} + +func startInternal(ctx1 context.Context, opts ...SpanOption) (span *Span, ctx context.Context) { span = &Span{ - id: NewSpanID(), - host: host, - startedTs: time.Now(), tags: map[string]interface{}{}, vals: map[string]interface{}{}, propagatedTags: map[string]interface{}{}, } + for _, opt := range SpanDefaults { + opt.apply(span) + } if p := CtxActiveSpan(ctx1); p != nil { span.parent = p @@ -74,7 +93,7 @@ func Start(ctx1 context.Context, opts ...SpanOption) (span *Span, ctx context.Co } if span.packageName == "" || span.className == "" || span.name == "" { - packageName, className, funcName := reflectutil.GetPackageClassFunc() + packageName, className, funcName := reflectutil.GetPackageClassFunc(3) if span.packageName == "" { span.packageName = packageName } @@ -89,41 +108,6 @@ func Start(ctx1 context.Context, opts ...SpanOption) (span *Span, ctx context.Co return span, context.WithValue(ctx1, activeSpanKey{}, span) } -// StartLeaf start new span without returning resulting context i.e. no child spans possibility -func StartLeaf(ctx context.Context, opts ...SpanOption) (span *Span) { - packageName, className, funcName := reflectutil.GetPackageClassFunc() - span, _ = Start(ctx, append([]SpanOption{ - WithName(funcName), - WithPackageClass(packageName, className), - }, opts...)...) - span.packageName = packageName - span.className = className - return span -} - -// Message is the simplest way to start a span, in the shortest way possible -// it doesn't use context, and doesn't return one. -// It is strongly discouraged to use Message unless for testing purposes. -func Message(message string, opts ...SpanOption) *Span { - packageName, className, funcName := reflectutil.GetPackageClassFunc() - span, _ := Start(context.Background(), append([]SpanOption{ - WithPackageClass(packageName, className), - WithName(funcName), - }, opts...)...) - span.Message(message) - return span -} - -// StartFromParentID starts new span with externally defined parent span ID -// Deprecated: use SpanOptions -func StartFromParentID(ctx context.Context, parentSpanID SpanID, traceID TraceID) (*Span, context.Context) { - p, c, f := reflectutil.GetPackageClassFunc() - span, ctx := Start(ctx, WithPackageClass(p, c), WithName(f)) - span.parentID = parentSpanID - span.traceID = traceID - return span, ctx -} - func (s *Span) ID() SpanID { return s.id } @@ -136,13 +120,14 @@ func (s *Span) Parent() *Span { return s.parent } -func (s *Span) Stop() { +func (s *Span) Stop() *Span { // no need to sync this, as the race won't matter if !s.finishedTs.IsZero() { - return + return s } s.finishedTs = time.Now() s.duration = s.finishedTs.Sub(s.startedTs) + return s } func (s *Span) IsFinished() bool { @@ -160,6 +145,10 @@ func (s *Span) StartedTs() time.Time { return s.startedTs } +func (s *Span) FinishedTs() time.Time { + return s.finishedTs +} + func (s *Span) Host() string { return s.host } @@ -290,12 +279,14 @@ type Enricher interface { Enrich(span *Span) *Span } -func (s *Span) EnrichFrom(e Enricher) *Span { - e.Enrich(s) +func (s *Span) EnrichFrom(ee ...Enricher) *Span { + for _, e := range ee { + e.Enrich(s) + } return s } -// Err adds error to the span, subsequent call combined errors +// Err adds error to the span, subsequent call combined errors, returns all combined errors func (s *Span) Err(err error) error { if err == nil { return nil @@ -305,7 +296,7 @@ func (s *Span) Err(err error) error { return err } s.errs = errs.Append(s.errs, err) - return err + return s.errs } // ErrWrapf shorthand for errors wrap @@ -335,6 +326,15 @@ func (s *Span) ErrSpan(err error) *Span { return s } +// ErrFinish convenience method to flush span with error and ignore otherwise +func (s *Span) ErrFinish(err error, trs Tracer) error { + if err == nil { + return nil + } + s.ErrSpan(err).FlushTo(trs) + return err +} + // DeferErr adds defer errors to span. Not the same as Err! func (s *Span) DeferErr(err error) *Span { if err == nil { @@ -368,9 +368,8 @@ func (s *Span) WarnWith(err error) error { return err } -// Message shorthand for generic Val("message", ... ) value -// overwrites previous message -// usage of specific tags and values is preferred! +// Message shorthand for generic Val("message", ... ) value, overwrites previous message +// usage of plain text messages is discouraged, use tags and values! func (s *Span) Message(message string) *Span { return s.Val("message", message) } @@ -382,6 +381,12 @@ func (s *Span) Level(level LogLevel) *Span { return s } +// LevelGet enhancement for better exporters and serializers implementations +// issue https://github.com/KasperskyLab/klogga/issues/7 +func (s *Span) LevelGet() LogLevel { + return s.level +} + // Tags get a copy of span tags func (s *Span) Tags() map[string]interface{} { result := make(map[string]interface{}) @@ -529,48 +534,18 @@ func (s *Span) EWState() string { return res } -func (s *Span) Json() ([]byte, error) { - if s == nil { - return nil, nil - } - - jsonStruct := struct { - ID SpanID - ParentID SpanID - TraceID TraceID - Ts string - Level string - PackageClass string - Name string - Duration time.Duration - Error error - DeferError error - Warn error - Tags map[string]interface{} - Vals map[string]interface{} - }{ - ID: s.id, - ParentID: s.parentID, - TraceID: s.traceID, - Ts: s.startedTs.Format(TimestampLayout), - Level: s.EWState(), - PackageClass: s.PackageClass(), - Name: s.name, - Duration: s.Duration(), - Error: s.Errs(), - DeferError: s.DeferErrs(), - Warn: s.Warns(), - Tags: s.Tags(), - Vals: s.Vals(), - } - return json.Marshal(&jsonStruct) -} - // FlushTo accept tracer and call trs.Finish, shorthand for chaining func (s *Span) FlushTo(trs Tracer) { trs.Finish(s) } +// FlushOnError if span has errors accept tracer and call trs.Finish +func (s *Span) FlushOnError(trs Tracer) { + if s.HasErr() || s.HasDeferErr() { + trs.Finish(s) + } +} + // CreateErrSpanFrom creates span describing an error in a flat way func CreateErrSpanFrom(ctx context.Context, span *Span) *Span { if !span.HasErr() { @@ -579,11 +554,13 @@ func CreateErrSpanFrom(ctx context.Context, span *Span) *Span { errSpan := StartLeaf(ctx, WithTraceID(span.TraceID())) errSpan.parent = span + errSpan.parentID = span.ID() errSpan.startedTs = span.StartedTs() errSpan.Tag("component", span.Component()) errSpan.host = span.Host() - errSpan.name = span.Name() + errSpan.packageName = span.Package() errSpan.className = span.Class() + errSpan.name = span.Name() errSpan.errs = span.errs errSpan.warns = span.warns errSpan.deferErrs = span.deferErrs diff --git a/span_defaults.go b/span_defaults.go new file mode 100644 index 0000000..7fdd293 --- /dev/null +++ b/span_defaults.go @@ -0,0 +1,10 @@ +package klogga + +// SpanDefaults is applied to all spans by default, before all other options +// initially created in response to https://github.com/KasperskyLab/klogga/issues/5 +// modify to change the default options +var SpanDefaults = []SpanOption{ + WithNewSpanID(), + WithTimestampNow(), + WithHostName(), +} diff --git a/span_fuzz_test.go b/span_fuzz_test.go new file mode 100644 index 0000000..dd20d19 --- /dev/null +++ b/span_fuzz_test.go @@ -0,0 +1,18 @@ +package klogga + +import ( + "context" + "testing" +) + +func FuzzTags(f *testing.F) { + f.Add("t1", "danila1") + f.Add("t2", "danila2") + f.Fuzz(func(t *testing.T, tag, tagValue string) { + spanStr := StartLeaf(context.Background()).Tag(tag, tagValue). + Stringify() + if spanStr == "" { + t.Errorf("tag=%s tagValue=%s", tag, tagValue) + } + }) +} diff --git a/span_json.go b/span_json.go new file mode 100644 index 0000000..8d0d498 --- /dev/null +++ b/span_json.go @@ -0,0 +1,42 @@ +package klogga + +import ( + "encoding/json" + "github.com/KasperskyLab/klogga/util/errs" +) + +func (s *Span) MarshalJSON() ([]byte, error) { + if s == nil { + return nil, nil + } + + jsonMap := map[string]any{} + + for k, v := range s.Tags() { + jsonMap[k] = v + } + for k, v := range s.Vals() { + jsonMap[k] = v + } + + jsonMap["id"] = s.ID() + jsonMap["parent_id"] = s.ParentID() + jsonMap["trace_id"] = s.TraceID() + jsonMap["started"] = s.StartedTs().Format(TimestampLayout) + jsonMap["duration"] = s.Duration() + jsonMap["level"] = s.level.String() + jsonMap["component"] = s.component + jsonMap["package_class"] = s.PackageClass() + jsonMap["name"] = s.Name() + jsonMap["error"] = errs.Append(s.Errs(), s.DeferErrs()) + jsonMap["warn"] = s.Warns() + jsonMap["tags"] = s.Tags() + jsonMap["vals"] = s.Vals() + + return json.Marshal(jsonMap) +} + +// Json DEPRECATED for compatibility with earlier versions +func (s *Span) Json() ([]byte, error) { + return s.MarshalJSON() +} diff --git a/span_opt.go b/span_opt.go index 1ca5418..68b08ee 100644 --- a/span_opt.go +++ b/span_opt.go @@ -6,6 +6,10 @@ type SpanOption interface { apply(*Span) } +type SpanOptionFunc func(*Span) + +func (f SpanOptionFunc) apply(span *Span) { f(span) } + type withTimestampOption struct { ts time.Time } @@ -20,6 +24,30 @@ func (o withTimestampOption) apply(span *Span) { span.startedTs = o.ts } +func WithTimestampUtcNow() SpanOption { + return (SpanOptionFunc)(func(span *Span) { + span.startedTs = time.Now().UTC() + }) +} + +func WithTimestampNow() SpanOption { + return (SpanOptionFunc)(func(span *Span) { + span.startedTs = time.Now() + }) +} + +func WithNewSpanID() SpanOption { + return (SpanOptionFunc)(func(span *Span) { + span.id = NewSpanID() + }) +} + +func WithHostName() SpanOption { + return (SpanOptionFunc)(func(span *Span) { + span.host = host + }) +} + type withNameOption struct { name string } diff --git a/span_test.go b/span_test.go index dc40ae6..4c68c35 100644 --- a/span_test.go +++ b/span_test.go @@ -54,7 +54,7 @@ func TestSpanJson(t *testing.T) { require.Empty(t, span.Component()) - bb, err := span.Json() + bb, err := span.MarshalJSON() require.NoError(t, err) str := string(bb) require.Contains(t, str, "danila") diff --git a/testdata/log.std.out.v5/logger.go b/testdata/log.std.out.v5/logger.go new file mode 100644 index 0000000..c6ec4e0 --- /dev/null +++ b/testdata/log.std.out.v5/logger.go @@ -0,0 +1,21 @@ +package loggers + +import ( + "context" + "github.com/KasperskyLab/klogga" +) + +type Logger struct{} + +func (r *Logger) Log(trsFactory klogga.TracerProvider) { + klogga.StartLeaf(context.Background()).Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Log2(trsFactory klogga.TracerProvider) { + span, _ := klogga.Start(context.Background()) + span.Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Message(trsFactory klogga.TracerProvider) { + klogga.Message("message").FlushTo(trsFactory.NamedPkg()) +} diff --git a/testdata/loggers.v4.0.1/logger.go b/testdata/loggers.v4.0.1/logger.go new file mode 100644 index 0000000..c6ec4e0 --- /dev/null +++ b/testdata/loggers.v4.0.1/logger.go @@ -0,0 +1,21 @@ +package loggers + +import ( + "context" + "github.com/KasperskyLab/klogga" +) + +type Logger struct{} + +func (r *Logger) Log(trsFactory klogga.TracerProvider) { + klogga.StartLeaf(context.Background()).Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Log2(trsFactory klogga.TracerProvider) { + span, _ := klogga.Start(context.Background()) + span.Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Message(trsFactory klogga.TracerProvider) { + klogga.Message("message").FlushTo(trsFactory.NamedPkg()) +} diff --git a/testdata/loggers.v4/logger.go b/testdata/loggers.v4/logger.go new file mode 100644 index 0000000..c6ec4e0 --- /dev/null +++ b/testdata/loggers.v4/logger.go @@ -0,0 +1,21 @@ +package loggers + +import ( + "context" + "github.com/KasperskyLab/klogga" +) + +type Logger struct{} + +func (r *Logger) Log(trsFactory klogga.TracerProvider) { + klogga.StartLeaf(context.Background()).Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Log2(trsFactory klogga.TracerProvider) { + span, _ := klogga.Start(context.Background()) + span.Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Message(trsFactory klogga.TracerProvider) { + klogga.Message("message").FlushTo(trsFactory.NamedPkg()) +} diff --git a/testdata/loggers/2.2.2/logger.go b/testdata/loggers/2.2.2/logger.go new file mode 100644 index 0000000..c6ec4e0 --- /dev/null +++ b/testdata/loggers/2.2.2/logger.go @@ -0,0 +1,21 @@ +package loggers + +import ( + "context" + "github.com/KasperskyLab/klogga" +) + +type Logger struct{} + +func (r *Logger) Log(trsFactory klogga.TracerProvider) { + klogga.StartLeaf(context.Background()).Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Log2(trsFactory klogga.TracerProvider) { + span, _ := klogga.Start(context.Background()) + span.Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Message(trsFactory klogga.TracerProvider) { + klogga.Message("message").FlushTo(trsFactory.NamedPkg()) +} diff --git a/testdata/loggers/logger.go b/testdata/loggers/logger.go new file mode 100644 index 0000000..c6ec4e0 --- /dev/null +++ b/testdata/loggers/logger.go @@ -0,0 +1,21 @@ +package loggers + +import ( + "context" + "github.com/KasperskyLab/klogga" +) + +type Logger struct{} + +func (r *Logger) Log(trsFactory klogga.TracerProvider) { + klogga.StartLeaf(context.Background()).Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Log2(trsFactory klogga.TracerProvider) { + span, _ := klogga.Start(context.Background()) + span.Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Message(trsFactory klogga.TracerProvider) { + klogga.Message("message").FlushTo(trsFactory.NamedPkg()) +} diff --git a/testdata/loggers/v2.1/logger.go b/testdata/loggers/v2.1/logger.go new file mode 100644 index 0000000..c6ec4e0 --- /dev/null +++ b/testdata/loggers/v2.1/logger.go @@ -0,0 +1,21 @@ +package loggers + +import ( + "context" + "github.com/KasperskyLab/klogga" +) + +type Logger struct{} + +func (r *Logger) Log(trsFactory klogga.TracerProvider) { + klogga.StartLeaf(context.Background()).Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Log2(trsFactory klogga.TracerProvider) { + span, _ := klogga.Start(context.Background()) + span.Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Message(trsFactory klogga.TracerProvider) { + klogga.Message("message").FlushTo(trsFactory.NamedPkg()) +} diff --git a/testdata/loggers/v2/logger.go b/testdata/loggers/v2/logger.go new file mode 100644 index 0000000..c6ec4e0 --- /dev/null +++ b/testdata/loggers/v2/logger.go @@ -0,0 +1,21 @@ +package loggers + +import ( + "context" + "github.com/KasperskyLab/klogga" +) + +type Logger struct{} + +func (r *Logger) Log(trsFactory klogga.TracerProvider) { + klogga.StartLeaf(context.Background()).Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Log2(trsFactory klogga.TracerProvider) { + span, _ := klogga.Start(context.Background()) + span.Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Message(trsFactory klogga.TracerProvider) { + klogga.Message("message").FlushTo(trsFactory.NamedPkg()) +} diff --git a/testdata/loggersv3/logger.go b/testdata/loggersv3/logger.go new file mode 100644 index 0000000..c6ec4e0 --- /dev/null +++ b/testdata/loggersv3/logger.go @@ -0,0 +1,21 @@ +package loggers + +import ( + "context" + "github.com/KasperskyLab/klogga" +) + +type Logger struct{} + +func (r *Logger) Log(trsFactory klogga.TracerProvider) { + klogga.StartLeaf(context.Background()).Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Log2(trsFactory klogga.TracerProvider) { + span, _ := klogga.Start(context.Background()) + span.Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Message(trsFactory klogga.TracerProvider) { + klogga.Message("message").FlushTo(trsFactory.NamedPkg()) +} diff --git a/testdata/nested/logger.go b/testdata/nested/logger.go new file mode 100644 index 0000000..722396e --- /dev/null +++ b/testdata/nested/logger.go @@ -0,0 +1,21 @@ +package nested + +import ( + "context" + "github.com/KasperskyLab/klogga" +) + +type Logger struct{} + +func (r *Logger) Log(trsFactory klogga.TracerProvider) { + klogga.StartLeaf(context.Background()).Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Log2(trsFactory klogga.TracerProvider) { + span, _ := klogga.Start(context.Background()) + span.Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Message(trsFactory klogga.TracerProvider) { + klogga.Message("message").FlushTo(trsFactory.NamedPkg()) +} diff --git a/testdata/nested/very/deep/logger.go b/testdata/nested/very/deep/logger.go new file mode 100644 index 0000000..7e9c486 --- /dev/null +++ b/testdata/nested/very/deep/logger.go @@ -0,0 +1,21 @@ +package deep + +import ( + "context" + "github.com/KasperskyLab/klogga" +) + +type Logger struct{} + +func (r *Logger) Log(trsFactory klogga.TracerProvider) { + klogga.StartLeaf(context.Background()).Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Log2(trsFactory klogga.TracerProvider) { + span, _ := klogga.Start(context.Background()) + span.Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Message(trsFactory klogga.TracerProvider) { + klogga.Message("message").FlushTo(trsFactory.NamedPkg()) +} diff --git a/testdata/nested/very/deep/v4/black/hole/logger.go b/testdata/nested/very/deep/v4/black/hole/logger.go new file mode 100644 index 0000000..cb8ff88 --- /dev/null +++ b/testdata/nested/very/deep/v4/black/hole/logger.go @@ -0,0 +1,21 @@ +package hole + +import ( + "context" + "github.com/KasperskyLab/klogga" +) + +type Logger struct{} + +func (r *Logger) Log(trsFactory klogga.TracerProvider) { + klogga.StartLeaf(context.Background()).Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Log2(trsFactory klogga.TracerProvider) { + span, _ := klogga.Start(context.Background()) + span.Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Message(trsFactory klogga.TracerProvider) { + klogga.Message("message").FlushTo(trsFactory.NamedPkg()) +} diff --git a/testdata/nested/very/deep/v4/black/hole/v6/loggers/logger.go b/testdata/nested/very/deep/v4/black/hole/v6/loggers/logger.go new file mode 100644 index 0000000..c6ec4e0 --- /dev/null +++ b/testdata/nested/very/deep/v4/black/hole/v6/loggers/logger.go @@ -0,0 +1,21 @@ +package loggers + +import ( + "context" + "github.com/KasperskyLab/klogga" +) + +type Logger struct{} + +func (r *Logger) Log(trsFactory klogga.TracerProvider) { + klogga.StartLeaf(context.Background()).Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Log2(trsFactory klogga.TracerProvider) { + span, _ := klogga.Start(context.Background()) + span.Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Message(trsFactory klogga.TracerProvider) { + klogga.Message("message").FlushTo(trsFactory.NamedPkg()) +} diff --git a/testdata/nested/very/deep/v4/black/hole/v6/loggers/v7/logger.go b/testdata/nested/very/deep/v4/black/hole/v6/loggers/v7/logger.go new file mode 100644 index 0000000..c6ec4e0 --- /dev/null +++ b/testdata/nested/very/deep/v4/black/hole/v6/loggers/v7/logger.go @@ -0,0 +1,21 @@ +package loggers + +import ( + "context" + "github.com/KasperskyLab/klogga" +) + +type Logger struct{} + +func (r *Logger) Log(trsFactory klogga.TracerProvider) { + klogga.StartLeaf(context.Background()).Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Log2(trsFactory klogga.TracerProvider) { + span, _ := klogga.Start(context.Background()) + span.Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Message(trsFactory klogga.TracerProvider) { + klogga.Message("message").FlushTo(trsFactory.NamedPkg()) +} diff --git a/testdata/nested/very/deep/v4/black/logger.go b/testdata/nested/very/deep/v4/black/logger.go new file mode 100644 index 0000000..7b9f784 --- /dev/null +++ b/testdata/nested/very/deep/v4/black/logger.go @@ -0,0 +1,21 @@ +package black + +import ( + "context" + "github.com/KasperskyLab/klogga" +) + +type Logger struct{} + +func (r *Logger) Log(trsFactory klogga.TracerProvider) { + klogga.StartLeaf(context.Background()).Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Log2(trsFactory klogga.TracerProvider) { + span, _ := klogga.Start(context.Background()) + span.Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Message(trsFactory klogga.TracerProvider) { + klogga.Message("message").FlushTo(trsFactory.NamedPkg()) +} diff --git a/testdata/nested/very/logger.go b/testdata/nested/very/logger.go new file mode 100644 index 0000000..587007e --- /dev/null +++ b/testdata/nested/very/logger.go @@ -0,0 +1,21 @@ +package very + +import ( + "context" + "github.com/KasperskyLab/klogga" +) + +type Logger struct{} + +func (r *Logger) Log(trsFactory klogga.TracerProvider) { + klogga.StartLeaf(context.Background()).Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Log2(trsFactory klogga.TracerProvider) { + span, _ := klogga.Start(context.Background()) + span.Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Message(trsFactory klogga.TracerProvider) { + klogga.Message("message").FlushTo(trsFactory.NamedPkg()) +} diff --git a/testdata/package_test.go b/testdata/package_test.go new file mode 100644 index 0000000..ffedf13 --- /dev/null +++ b/testdata/package_test.go @@ -0,0 +1,79 @@ +package testdata + +import ( + "context" + "github.com/KasperskyLab/klogga" + loggers5 "github.com/KasperskyLab/klogga/testdata/log.std.out.v5" + "github.com/KasperskyLab/klogga/testdata/loggers" + loggers4 "github.com/KasperskyLab/klogga/testdata/loggers.v4" + loggers401 "github.com/KasperskyLab/klogga/testdata/loggers.v4.0.1" + loggers222 "github.com/KasperskyLab/klogga/testdata/loggers/2.2.2" + loggers2 "github.com/KasperskyLab/klogga/testdata/loggers/v2" + loggers21 "github.com/KasperskyLab/klogga/testdata/loggers/v2.1" + loggersv3 "github.com/KasperskyLab/klogga/testdata/loggersv3" + "github.com/KasperskyLab/klogga/testdata/nested" + "github.com/KasperskyLab/klogga/testdata/nested/very" + "github.com/KasperskyLab/klogga/testdata/nested/very/deep" + "github.com/KasperskyLab/klogga/testdata/nested/very/deep/v4/black" + "github.com/KasperskyLab/klogga/testdata/nested/very/deep/v4/black/hole" + loggersv6 "github.com/KasperskyLab/klogga/testdata/nested/very/deep/v4/black/hole/v6/loggers" + loggersv7 "github.com/KasperskyLab/klogga/testdata/nested/very/deep/v4/black/hole/v6/loggers/v7" + "github.com/KasperskyLab/klogga/testdata/parent/child" + "github.com/stretchr/testify/require" + "testing" +) + +func TestVersionPackages(t *testing.T) { + type iLogger interface { + Log(trsFactory klogga.TracerProvider) + Log2(trsFactory klogga.TracerProvider) + Message(trsFactory klogga.TracerProvider) + } + for _, ts := range []struct { + logger iLogger + expect string + }{ + {logger: new(loggers.Logger), expect: "loggers"}, + {logger: new(loggers2.Logger), expect: "loggers"}, + {logger: new(loggers4.Logger), expect: "loggers"}, + {logger: new(loggers401.Logger), expect: "loggers"}, + {logger: new(loggers222.Logger), expect: "loggers"}, + {logger: new(loggers21.Logger), expect: "loggers"}, + {logger: new(loggers5.Logger), expect: "log.std.out"}, + {logger: new(loggersv3.Logger), expect: "loggersv3"}, + {logger: new(loggersv6.Logger), expect: "loggers"}, + {logger: new(loggersv7.Logger), expect: "loggers"}, + {logger: new(nested.Logger), expect: "nested"}, + {logger: new(very.Logger), expect: "very"}, + {logger: new(deep.Logger), expect: "deep"}, + {logger: new(black.Logger), expect: "black"}, + {logger: new(hole.Logger), expect: "hole"}, + {logger: new(child.Logger), expect: "parent"}, + } { + tf := klogga.NewFactory(newExporter(t, ts.expect)) + ts.logger.Log(tf) + ts.logger.Log2(tf) + ts.logger.Message(tf) + } +} + +type exporter struct { + t *testing.T + expectedPackage string +} + +func newExporter(t *testing.T, expectedPackage string) *exporter { + t.Helper() + return &exporter{t: t, expectedPackage: expectedPackage} +} + +func (e exporter) Write(ctx context.Context, spans []*klogga.Span) error { + for _, span := range spans { + require.Equal(e.t, e.expectedPackage, span.Package()) + } + return nil +} + +func (e exporter) Shutdown(context.Context) error { + return nil +} diff --git a/testdata/parent/child/child.go b/testdata/parent/child/child.go new file mode 100644 index 0000000..babe98f --- /dev/null +++ b/testdata/parent/child/child.go @@ -0,0 +1,7 @@ +package child + +import "github.com/KasperskyLab/klogga/testdata/parent" + +type Logger struct { + parent.Logger +} diff --git a/testdata/parent/parent.go b/testdata/parent/parent.go new file mode 100644 index 0000000..8de4dca --- /dev/null +++ b/testdata/parent/parent.go @@ -0,0 +1,21 @@ +package parent + +import ( + "context" + "github.com/KasperskyLab/klogga" +) + +type Logger struct{} + +func (r *Logger) Log(trsFactory klogga.TracerProvider) { + klogga.StartLeaf(context.Background()).Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Log2(trsFactory klogga.TracerProvider) { + span, _ := klogga.Start(context.Background()) + span.Val("run", "test").FlushTo(trsFactory.NamedPkg()) +} + +func (r *Logger) Message(trsFactory klogga.TracerProvider) { + klogga.Message("message").FlushTo(trsFactory.NamedPkg()) +} diff --git a/testdata/testpkg/v2/span_test.go b/testdata/testpkg/v2/span_test.go new file mode 100644 index 0000000..9f77983 --- /dev/null +++ b/testdata/testpkg/v2/span_test.go @@ -0,0 +1,11 @@ +package testpkg + +import ( + "github.com/stretchr/testify/require" + "testing" +) + +func TestVersionedPackageName(t *testing.T) { + span := CreateMySpan() + require.Equal(t, "testpkg", span.Package()) +} diff --git a/testdata/testpkg/v2/testpkg.go b/testdata/testpkg/v2/testpkg.go new file mode 100644 index 0000000..952b232 --- /dev/null +++ b/testdata/testpkg/v2/testpkg.go @@ -0,0 +1,11 @@ +package testpkg + +import ( + "context" + "github.com/KasperskyLab/klogga" +) + +func CreateMySpan() *klogga.Span { + span, _ := klogga.Start(context.Background()) + return span +} diff --git a/util/defaults.go b/util/defaults.go new file mode 100644 index 0000000..a121caf --- /dev/null +++ b/util/defaults.go @@ -0,0 +1,10 @@ +package util + +import ( + "github.com/KasperskyLab/klogga" + "github.com/KasperskyLab/klogga/exporters/golog" +) + +func DefaultFactory() *klogga.Factory { + return klogga.NewFactory(golog.New(nil)) +} diff --git a/util/errs/errs_test.go b/util/errs/errs_test.go index c2e09e4..c244e17 100644 --- a/util/errs/errs_test.go +++ b/util/errs/errs_test.go @@ -8,11 +8,12 @@ import ( func TestAppend(t *testing.T) { require.Nil(t, Append(nil, nil)) + require.Nil(t, Append(nil, nil, nil)) require.NotNil(t, Append(errors.New("err"), nil)) require.NotNil(t, Append(nil, errors.New("err"))) } -func TestAppenManyNils(t *testing.T) { +func TestAppendManyNils(t *testing.T) { source := errors.New("err") err := Append(nil, nil, nil, source) require.NotNil(t, err) diff --git a/util/reflectutil/reflectutil.go b/util/reflectutil/reflectutil.go index aa9aca2..16dd74e 100644 --- a/util/reflectutil/reflectutil.go +++ b/util/reflectutil/reflectutil.go @@ -1,35 +1,116 @@ package reflectutil import ( + "net/url" "reflect" "runtime" "strings" + + "github.com/hashicorp/go-version" ) +const pathSeparator = string("/") + // GetPackageClassFunc parses package (last entry in the path), // class(==receiver type) and func for the call one level up -func GetPackageClassFunc() (string, string, string) { - pc := make([]uintptr, 10) - runtime.Callers(2, pc) +func GetPackageClassFunc(skip int) (string, string, string) { + pc, _, _, _ := runtime.Caller(skip) - fnc := runtime.FuncForPC(pc[1]) + fnc := runtime.FuncForPC(pc) + // We have something like "path.to/my/pkg.MyFunction". If the function is + // a closure, it is something like, "path.to/my/pkg.MyFunction.func1". fullName := fnc.Name() // remove path to package - i := strings.LastIndex(fullName, "/") - if i >= 0 && i+1 < len(fullName) { - fullName = fullName[i+1:] - } - - split := strings.Split(fullName, ".") + // Everything up to the first "." after the last "/" is the package name. + // Everything after the "." is the full function name. + shortName, rest := base(fullName, pathSeparator) + split := strings.Split(shortName, ".") if len(split) >= 3 { - return split[0], cleanReceiver(split[1]), split[2] + return ParsePackageName(rest + pathSeparator + split[0]), cleanReceiver(split[1]), split[2] } if len(split) == 2 { - return split[0], "", split[1] + return ParsePackageName(rest + pathSeparator + split[0]), "", split[1] } - return fullName, "", "" + return ParsePackageName(fullName), "", "" +} + +// ParsePackageName determines the package name based on the path to it. Recognizes and ignores library versioning +// specified via /v* or .v*. Not able to determine the real name of the package, it relies on the folder in which +// the package is located, ignoring the folder for versioning(like /v2) or its suffix(like .v2). If the package name is +// packageA and it is in the folder packageB, then the package will be recognized as packageB. +// Returns the query decoded package name +// implemented in response for issue https://github.com/KasperskyLab/klogga/issues/8 +func ParsePackageName(fullPath string) string { + pkgName, parentDir := base(fullPath, pathSeparator) + if pkgName == "" { + return pkgName + } + // Package names are URL-encoded to avoid ambiguity in the case where the + // package name contains ".git". Otherwise, "foo/bar.git.MyFunction" would + // mean that "git" is the top-level function and "MyFunction" is embedded + // inside it. + if unescaped, err := url.QueryUnescape(pkgName); err == nil { + pkgName = unescaped + } + + // https://go.dev/ref/mod#major-version-suffixes + // Starting with major version 2, module paths must have a major version suffix like /v2 that matches the major + // version. For example, if a module has the path example.com/mod at v1.0.0, it must have the path example.com/mod/v2 + // at version v2.0.0. + // + // As a special case, modules paths starting with gopkg.in/ must always have a major version suffix, even at v0 and + // v1. The suffix must start with a dot rather than a slash (for example, gopkg.in/yaml.v2). + + var foundPkgName string + + // detect /v2 version, like google-api-go-client/blob/main/slides/v1 + checkVersion := pkgName + if checkVersion[0] == 'v' { + checkVersion = checkVersion[1:] + } + if _, err := version.NewVersion(checkVersion); err == nil { + foundPkgName, _ = base(parentDir, pathSeparator) + } else { + // detect .v2 version, like gopkg.in/yaml.v2 + right, left := base(pkgName, ".v") + if right != "" { + if _, err := version.NewVersion(right); err == nil { + foundPkgName = left + } + } + } + if foundPkgName == "" { + foundPkgName = pkgName + } + + // It has been a common practice in the past to name go package repositories either with go- prefix + // (like go-bindata or go-iter,…), so remove this prefix if meet + // https://groups.google.com/g/golang-nuts/c/WMVf2Acq6JQ?pli=1 + // Also this prefix can be in suffix, like in aws/smithy-go or edsrzf/mmap-go + // Also this prefix can be golang-(hashicorp/golang-lru) or go.(satori/go.uuid) + return trimPrefix(strings.TrimSuffix(foundPkgName, "-go"), "go-", "golang-", "go.") +} + +// trimPrefix removes one of the prefixes, does not remove more than one prefix at a time +func trimPrefix(str string, prefixes ...string) string { + originLen := len(str) + for _, prefix := range prefixes { + str = strings.TrimPrefix(str, prefix) + if len(str) != originLen { + return str + } + } + return str +} + +func base(fullName, separator string) (name string, dir string) { + i := strings.LastIndex(fullName, separator) + if i < 0 || i >= len(fullName)-1 { + return fullName, "" + } + return fullName[i+len(separator):], fullName[:i] } func cleanReceiver(c string) string { @@ -40,5 +121,13 @@ func cleanReceiver(c string) string { // IsNil universal check for nil // https://medium.com/@glucn/golang-an-interface-holding-a-nil-value-is-not-nil-bb151f472cc7 func IsNil(i interface{}) bool { - return i == nil || (reflect.ValueOf(i).Kind() == reflect.Ptr && reflect.ValueOf(i).IsNil()) + if reflect.TypeOf(i) == nil { + return true + } + switch reflect.ValueOf(i).Kind() { + // this set of types was taken from reflect.Value.IsNil() + case reflect.Chan, reflect.Func, reflect.Map, reflect.Pointer, reflect.UnsafePointer, reflect.Slice, reflect.Interface: + return reflect.ValueOf(i).IsNil() + } + return false } diff --git a/util/reflectutil/reflectutil_test.go b/util/reflectutil/reflectutil_test.go index 1376fe6..d788aa1 100644 --- a/util/reflectutil/reflectutil_test.go +++ b/util/reflectutil/reflectutil_test.go @@ -5,6 +5,39 @@ import ( "testing" ) +func TestIsNil(t *testing.T) { + var ( + nilObj *int + nilInterface interface{} + nilSlice []int + nilMap map[int]int + nilChan chan int + nilFunc func() + ) + for _, obj := range []interface{}{nilObj, nilInterface, nilSlice, nilMap, nilChan, nilFunc} { + require.True(t, IsNil(obj), obj) + } + + var ( + number int + str string + floatNum float32 + b byte + pointer = &nilObj + array [2]int + noneNilMap = make(map[int]int) + noneNilSlice = make([]int, 0) + noneNilChan = make(chan int) + noneNilInterface interface{} = b + noneNilFunc = func() {} + ) + for _, obj := range []interface{}{ + number, str, floatNum, b, pointer, array, noneNilMap, noneNilSlice, noneNilChan, noneNilInterface, noneNilFunc, + } { + require.False(t, IsNil(obj), obj) + } +} + func TestGetClass(t *testing.T) { c := La{} require.Equal(t, "La", c.DoStuff()) @@ -17,7 +50,7 @@ func TestGetClass(t *testing.T) { func TestGetFunc(t *testing.T) { func() { - p, c, f := GetPackageClassFunc() + p, c, f := GetPackageClassFunc(2) require.Equal(t, "reflectutil", p) require.Equal(t, "", c) require.Equal(t, "TestGetFunc", f) @@ -26,7 +59,7 @@ func TestGetFunc(t *testing.T) { // go:noinline func getClass() string { - _, c, _ := GetPackageClassFunc() + _, c, _ := GetPackageClassFunc(2) return c } diff --git a/util/testutil/timeout.go b/util/testutil/timeout.go index 4b39341..c4244db 100644 --- a/util/testutil/timeout.go +++ b/util/testutil/timeout.go @@ -5,8 +5,14 @@ import ( "time" ) -func Timeout() context.Context { +// Timeout context with timeout for tests +// optional parameter - timeout duration, default is 5 seconds +func Timeout(d ...time.Duration) context.Context { + dd := 5 * time.Second + if len(d) >= 1 { + dd = d[0] + } //nolint:govet // cancel not needed in tests - timeout, _ := context.WithTimeout(context.Background(), 5*time.Second) + timeout, _ := context.WithTimeout(context.Background(), dd) return timeout } diff --git a/utils.go b/utils.go index 4b80791..f892803 100644 --- a/utils.go +++ b/utils.go @@ -32,6 +32,8 @@ func (w WriterExporter) Shutdown(context.Context) error { } // WriterTracer adapts tracer to a Writer interface +// each call to Write writes all bytes as string to Message function +// intended as an adapter for simplest logging systems that understand only io.Writer interface type WriterTracer struct { trs Tracer }