Skip to content

Commit

Permalink
autoconfigure module (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
chameleon82 authored Aug 5, 2023
1 parent d9025a7 commit 54fb2ae
Show file tree
Hide file tree
Showing 12 changed files with 552 additions and 22 deletions.
42 changes: 27 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ No Logs Pull Requests are currently being accepted.
This project will be deprecated once official [opentelemetry-go](https://github.com/open-telemetry/opentelemetry-go)
repository Logs module will have status "Stable".

## Project packages

| Packages | Description |
|----------------------------------|----------------------------------------------------------------------------|
| [autoconfigure](./autoconfigure) | Autoconfiguration SDK. Allow to configure log exporters with env variables |
| [sdk](./sdk) | Opentelemetry Logs SDK |
| [exporters/otlp](./exporters) | OTLP format exporter |
| [exporters/stdout](./exporters) | Console exporter |

## Quick start

This is an implementation of [Logs Bridge API](https://opentelemetry.io/docs/specs/otel/logs/bridge-api/) and not
Expand All @@ -35,26 +44,26 @@ import (
)

const (
instrumentationName = "otel/zap"
instrumentationVersion = "0.0.1"
instrumentationName = "otel/zap"
instrumentationVersion = "0.0.1"
)

var (
logger = otel.GetLoggerProvider().Logger(
instrumentationName,
logs.WithInstrumentationVersion(instrumentationVersion),
logs.WithSchemaURL(semconv.SchemaURL),
)
logger = otel.GetLoggerProvider().Logger(
instrumentationName,
logs.WithInstrumentationVersion(instrumentationVersion),
logs.WithSchemaURL(semconv.SchemaURL),
)
)

func (c otlpCore) Write(ent zapcore.Entry, fields []zapcore.Field) error {
lrc := logs.LogRecordConfig{
Body: &ent.Message,
...
}
logRecord := logs.NewLogRecord(lrc)
logger.Emit(logRecord)

lrc := logs.LogRecordConfig{
Body: &ent.Message,
...
}
logRecord := logs.NewLogRecord(lrc)
logger.Emit(logRecord)
}
```

Expand All @@ -64,6 +73,7 @@ and application initialization code:
package main

import (
"os"
"context"
"github.com/agoda-com/opentelemetry-logs-go"
"github.com/agoda-com/opentelemetry-logs-go/exporters/otlp/otlplogs"
Expand All @@ -74,10 +84,12 @@ import (
)

func newResource() *resource.Resource {
host, _ := os.Hostname()
return resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName("otlplogs-example"),
semconv.ServiceVersion("0.0.1"),
semconv.HostName(host),
)
}

Expand All @@ -90,7 +102,7 @@ func main() {
sdk.WithResource(newResource()),
)
otel.SetLoggerProvider(loggerProvider)

myInstrumentedLogger.Info("Hello OpenTelemetry")
}
```
Expand Down
170 changes: 170 additions & 0 deletions autoconfigure/README.md

Large diffs are not rendered by default.

45 changes: 45 additions & 0 deletions autoconfigure/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
module github.com/agoda-com/opentelemetry-logs-go/autoconfigure

go 1.19

require (
github.com/agoda-com/opentelemetry-logs-go/exporters/otlp/otlplogs v0.0.1
github.com/agoda-com/opentelemetry-logs-go/exporters/stdout/stdoutlogs v0.0.1
github.com/agoda-com/opentelemetry-logs-go/sdk v0.0.1
github.com/stretchr/testify v1.8.4
)

require (
github.com/agoda-com/opentelemetry-logs-go v0.0.1 // indirect
github.com/agoda-com/opentelemetry-logs-go/exporters/otlp/internal/retry v0.0.1 // indirect
github.com/agoda-com/opentelemetry-logs-go/logs v0.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.opentelemetry.io/otel v1.16.0 // indirect
go.opentelemetry.io/otel/metric v1.16.0 // indirect
go.opentelemetry.io/otel/sdk v1.16.0 // indirect
go.opentelemetry.io/otel/trace v1.16.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/text v0.9.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/grpc v1.57.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

replace (
github.com/agoda-com/opentelemetry-logs-go => ../
github.com/agoda-com/opentelemetry-logs-go/exporters/otlp/internal/retry => ../exporters/otlp/internal/retry
github.com/agoda-com/opentelemetry-logs-go/exporters/otlp/otlplogs => ../exporters/otlp/otlplogs
github.com/agoda-com/opentelemetry-logs-go/exporters/stdout/stdoutlogs => ../exporters/stdout/stdoutlogs
github.com/agoda-com/opentelemetry-logs-go/logs => ../logs
github.com/agoda-com/opentelemetry-logs-go/sdk => ../sdk
)
57 changes: 57 additions & 0 deletions autoconfigure/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/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/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo=
go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4=
go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE=
go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4=
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e h1:Ao9GzfUMPH3zjVfzXG5rlWlk+Q8MXWKwWpwVQE1MXfw=
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM=
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw=
google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
21 changes: 21 additions & 0 deletions autoconfigure/sdk/logs/exporter_env.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package logs

import (
"os"
"strings"
)

const (
// see https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#exporter-selection
logsExporterKey = "OTEL_LOGS_EXPORTER"

logsExporterNone = "none"
logsExporterOTLP = "otlp"
logsExporterLogging = "logging"
)

func exportersFromEnv() ([]string, bool) {
exportersEnv, defined := os.LookupEnv(logsExporterKey)
exporters := strings.Split(exportersEnv, ",")
return exporters, defined
}
111 changes: 111 additions & 0 deletions autoconfigure/sdk/logs/provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package logs

import (
"context"
"errors"
"github.com/agoda-com/opentelemetry-logs-go/exporters/otlp/otlplogs"
"github.com/agoda-com/opentelemetry-logs-go/exporters/stdout/stdoutlogs"
"github.com/agoda-com/opentelemetry-logs-go/internal/global"
sdk "github.com/agoda-com/opentelemetry-logs-go/sdk/logs"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/sdk/resource"
)

// loggerProviderConfig Configuration for Logger Provider
type loggerProviderConfig struct {
processors []sdk.LogRecordProcessor
// resource contains attributes representing an entity that produces telemetry.
resource *resource.Resource
}

// LoggerProviderOption configures a LoggerProvider.
type LoggerProviderOption interface {
apply(loggerProviderConfig) loggerProviderConfig
}
type loggerProviderOptionFunc func(loggerProviderConfig) loggerProviderConfig

func (fn loggerProviderOptionFunc) apply(cfg loggerProviderConfig) loggerProviderConfig {
return fn(cfg)
}

// WithLogRecordProcessors will configure processor to process logs
func WithLogRecordProcessors(logsProcessors []sdk.LogRecordProcessor) LoggerProviderOption {
return loggerProviderOptionFunc(func(cfg loggerProviderConfig) loggerProviderConfig {
cfg.processors = logsProcessors
return cfg
})
}

// WithResource will configure OTLP logger with common resource attributes.
//
// Parameters:
// r (*resource.Resource) list of resources will be added to every log as resource level tags
func WithResource(r *resource.Resource) LoggerProviderOption {
return loggerProviderOptionFunc(func(cfg loggerProviderConfig) loggerProviderConfig {
var err error
cfg.resource, err = resource.Merge(resource.Environment(), r)
if err != nil {
otel.Handle(err)
}
return cfg
})
}

//type loggerProviderConfig struct {
// options []sdk.LoggerProviderOption
//}

func applyLoggerProviderExporterEnvConfigs(ctx context.Context, cfg loggerProviderConfig) loggerProviderConfig {

// if processors already defined explicitly - skip env configuration
if cfg.processors != nil {
return cfg
}

exporters, isProvided := exportersFromEnv()
if isProvided == false || len(exporters) == 0 {
exporters = []string{logsExporterOTLP}
}

// currently values are hardcoded, but subject to be extracted into global map to LoggerProviderOption
// to support custom exporters
for _, exporter := range exporters {
switch exporter {
case logsExporterNone:
case logsExporterOTLP:
otlpExporter, err := otlplogs.NewExporter(ctx)
global.Error(err, "Can't instantiate otlp exporter")
cfg.processors = append(cfg.processors, sdk.NewBatchLogRecordProcessor(otlpExporter))
case logsExporterLogging:
sdtoutExporter, err := stdoutlogs.NewExporter()
global.Error(err, "Can't instantiate logging exporter")
cfg.processors = append(cfg.processors, sdk.NewSimpleLogRecordProcessor(sdtoutExporter))
default:
err := errors.New("Exporter " + exporter + " is not supported")
global.Error(err, "Can't instantiate "+exporter+" exporter")
}
}
return cfg
}

// NewLoggerProvider will autoconfigure exporters and create logger provider
func NewLoggerProvider(ctx context.Context, opts ...LoggerProviderOption) *sdk.LoggerProvider {

o := loggerProviderConfig{}

for _, opt := range opts {
o = opt.apply(o)
}

// apply exporter env options after as should not instantiate exporters if they will be overridden
o = applyLoggerProviderExporterEnvConfigs(ctx, o)

var sdkOptions []sdk.LoggerProviderOption

for _, processor := range o.processors {
sdkOptions = append(sdkOptions, sdk.WithLogRecordProcessor(processor))
}
sdkOptions = append(sdkOptions, sdk.WithResource(o.resource))

return sdk.NewLoggerProvider(sdkOptions...)
}
54 changes: 54 additions & 0 deletions autoconfigure/sdk/logs/provider_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package logs_test

import (
"context"
otel "github.com/agoda-com/opentelemetry-logs-go"
autosdk "github.com/agoda-com/opentelemetry-logs-go/autoconfigure/sdk/logs"
"github.com/agoda-com/opentelemetry-logs-go/logs"
sdk "github.com/agoda-com/opentelemetry-logs-go/sdk/logs"
"github.com/stretchr/testify/assert"
semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
"testing"
"time"
)

const (
instrumentationName = "github.com/instrumentron"
instrumentationVersion = "v0.1.0"
)

func doSomething() {
logger := otel.GetLoggerProvider().Logger(
instrumentationName,
logs.WithInstrumentationVersion(instrumentationVersion),
logs.WithSchemaURL(semconv.SchemaURL),
)

body := "My message"
now := time.Now()
sn := logs.INFO
cfg := logs.LogRecordConfig{
Timestamp: &now,
ObservedTimestamp: now,
Body: &body,
SeverityNumber: &sn,
}
logRecord := logs.NewLogRecord(cfg)
logger.Emit(logRecord)
}
func TestProvider(t *testing.T) {
ctx := context.Background()
provider, _ := autosdk.NewLoggerProvider(ctx)
defer func(provider *sdk.LoggerProvider, ctx context.Context) {
err := provider.Shutdown(ctx)
if err != nil {

}
}(provider, ctx)

otel.SetLoggerProvider(provider)

doSomething()

assert.NoError(t, provider.Shutdown(ctx))
}
Loading

0 comments on commit 54fb2ae

Please sign in to comment.