-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding a trace exporter to Azure Monitor (#39)
* Adding a trace exporter to Azure Monitor This exporter transforms the current wire format Spans into constructs defined in [ApplicationInsights-Go](github.com/Microsoft/ApplicationInsights-Go/appinsights/contracts). Once a Span is transformed it is sent to Azure Monitor via a transportChannel interface. There is an implementation of that interface method inside ApplicationInsights-Go package that ultimately ultimately sent to Azure Monitor via a REST API. This package takes care of appropriate retries, batching, and buffering (in-memory only). Once the OpenTelemetry wire format is incorporated into the collector I will make the switch to that format. The changes should not be too bad. This PR does not: - export Span events - export Span links, - implement a metrics exporter Test code coverage is > 90% * Wiring up the Azure Monitor exporter via local module redirect * Adding slightly more test coverage * Addressing some PR comments * Rename toHex -> idToHex * Address more PR comments * Plumb zap.Logger through to the exporter * Satisfy impi import validation * Sanitize envelope fix * Numeric attribute values -> measurements collection * Remove the exporter Debug configuration flag and just use the information available in the zap.Logger * Adding a config validation check * Addressing PR comments
- Loading branch information
Showing
17 changed files
with
2,448 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include ../../Makefile.Common |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Copyright 2019, OpenTelemetry Authors | ||
// | ||
// 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. | ||
|
||
package azuremonitorexporter | ||
|
||
import "github.com/Microsoft/ApplicationInsights-Go/appinsights/contracts" | ||
|
||
type transportChannel interface { | ||
Send(*contracts.Envelope) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Copyright 2019, OpenTelemetry Authors | ||
// | ||
// 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. | ||
|
||
package azuremonitorexporter | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/open-telemetry/opentelemetry-collector/config/configmodels" | ||
) | ||
|
||
// Config defines configuration for Azure Monitor | ||
type Config struct { | ||
// squash ensures fields are correctly decoded in embedded struct. | ||
configmodels.ExporterSettings `mapstructure:",squash"` | ||
Endpoint string `mapstructure:"endpoint"` | ||
InstrumentationKey string `mapstructure:"instrumentation_key"` | ||
MaxBatchSize int `mapstructure:"maxbatchsize"` | ||
MaxBatchInterval time.Duration `mapstructure:"maxbatchinterval"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// Copyright 2019, OpenTelemetry Authors | ||
// | ||
// 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. | ||
|
||
package azuremonitorexporter | ||
|
||
import ( | ||
"path" | ||
"testing" | ||
"time" | ||
|
||
"github.com/open-telemetry/opentelemetry-collector/config" | ||
"github.com/open-telemetry/opentelemetry-collector/config/configcheck" | ||
"github.com/open-telemetry/opentelemetry-collector/config/configmodels" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestLoadConfig(t *testing.T) { | ||
factories, err := config.ExampleComponents() | ||
assert.Nil(t, err) | ||
|
||
factory := &Factory{} | ||
factories.Exporters[typeStr] = factory | ||
cfg, err := config.LoadConfigFile( | ||
t, path.Join(".", "testdata", "config.yaml"), factories, | ||
) | ||
|
||
require.NoError(t, err) | ||
require.NotNil(t, cfg) | ||
|
||
assert.Equal(t, len(cfg.Exporters), 2) | ||
|
||
exporterType := typeStr | ||
exporter := cfg.Exporters[exporterType] | ||
assert.Equal(t, factory.CreateDefaultConfig(), exporter) | ||
|
||
exporterType = typeStr + "/2" | ||
exporter = cfg.Exporters[exporterType].(*Config) | ||
assert.NoError(t, configcheck.ValidateConfig(exporter)) | ||
assert.Equal( | ||
t, | ||
&Config{ | ||
ExporterSettings: configmodels.ExporterSettings{TypeVal: typeStr, NameVal: exporterType}, | ||
Endpoint: defaultEndpoint, | ||
InstrumentationKey: "abcdefg", | ||
MaxBatchSize: 100, | ||
MaxBatchInterval: 10 * time.Second, | ||
}, | ||
exporter) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
// Copyright 2019, OpenTelemetry Authors | ||
// | ||
// 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. | ||
|
||
package azuremonitorexporter | ||
|
||
import ( | ||
"errors" | ||
"time" | ||
|
||
"github.com/Microsoft/ApplicationInsights-Go/appinsights" | ||
"github.com/open-telemetry/opentelemetry-collector/config/configerror" | ||
"github.com/open-telemetry/opentelemetry-collector/config/configmodels" | ||
"github.com/open-telemetry/opentelemetry-collector/exporter" | ||
"go.uber.org/zap" | ||
) | ||
|
||
const ( | ||
// The value of "type" key in configuration. | ||
typeStr = "azuremonitor" | ||
defaultEndpoint = "https://dc.services.visualstudio.com/v2/track" | ||
) | ||
|
||
var ( | ||
errUnexpectedConfigurationType = errors.New("failed to cast configuration to Azure Monitor Config") | ||
) | ||
|
||
// Factory for Azure Monitor exporter. | ||
// Implements the interface from github.com/open-telemetry/opentelemetry-collector/exporter/factory.go | ||
type Factory struct { | ||
TransportChannel transportChannel | ||
} | ||
|
||
// Type gets the type of the Exporter config created by this factory. | ||
func (f *Factory) Type() string { | ||
return typeStr | ||
} | ||
|
||
// CreateDefaultConfig creates the default configuration for exporter. | ||
func (f *Factory) CreateDefaultConfig() configmodels.Exporter { | ||
|
||
return &Config{ | ||
ExporterSettings: configmodels.ExporterSettings{ | ||
TypeVal: typeStr, | ||
NameVal: typeStr, | ||
}, | ||
Endpoint: defaultEndpoint, | ||
MaxBatchSize: 1024, | ||
MaxBatchInterval: 10 * time.Second, | ||
} | ||
} | ||
|
||
// CreateTraceExporter creates a trace exporter based on this config. | ||
func (f *Factory) CreateTraceExporter(logger *zap.Logger, config configmodels.Exporter) (exporter.TraceExporter, error) { | ||
exporterConfig, ok := config.(*Config) | ||
|
||
if !ok { | ||
return nil, errUnexpectedConfigurationType | ||
} | ||
|
||
transportChannel := f.getTransportChannel(exporterConfig, logger) | ||
return newTraceExporter(exporterConfig, transportChannel, logger) | ||
} | ||
|
||
// CreateMetricsExporter creates a metrics exporter based on this config. | ||
func (f *Factory) CreateMetricsExporter( | ||
logger *zap.Logger, | ||
cfg configmodels.Exporter, | ||
) (exporter.MetricsExporter, error) { | ||
return nil, configerror.ErrDataTypeIsNotSupported | ||
} | ||
|
||
// Configures the transport channel. | ||
// This method is not thread-safe | ||
func (f *Factory) getTransportChannel(exporterConfig *Config, logger *zap.Logger) transportChannel { | ||
|
||
// The default transport channel uses the default send mechanism from the AppInsights telemetry client. | ||
// This default channel handles batching, appropriate retries, and is backed by memory. | ||
if f.TransportChannel == nil { | ||
telemetryConfiguration := appinsights.NewTelemetryConfiguration(exporterConfig.InstrumentationKey) | ||
telemetryConfiguration.EndpointUrl = exporterConfig.Endpoint | ||
telemetryConfiguration.MaxBatchSize = exporterConfig.MaxBatchSize | ||
telemetryConfiguration.MaxBatchInterval = exporterConfig.MaxBatchInterval | ||
telemetryClient := appinsights.NewTelemetryClientFromConfig(telemetryConfiguration) | ||
|
||
f.TransportChannel = telemetryClient.Channel() | ||
|
||
// Don't even bother enabling the AppInsights diagnostics listener unless debug logging is enabled | ||
if checkedEntry := logger.Check(zap.DebugLevel, ""); checkedEntry != nil { | ||
appinsights.NewDiagnosticsMessageListener(func(msg string) error { | ||
logger.Debug(msg) | ||
return nil | ||
}) | ||
} | ||
} | ||
|
||
return f.TransportChannel | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// Copyright 2019, OpenTelemetry Authors | ||
// | ||
// 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. | ||
|
||
package azuremonitorexporter | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/open-telemetry/opentelemetry-collector/config/configerror" | ||
"github.com/stretchr/testify/assert" | ||
"go.uber.org/zap" | ||
) | ||
|
||
func TestExporterTypeKey(t *testing.T) { | ||
factory := Factory{} | ||
|
||
assert.Equal(t, typeStr, factory.Type()) | ||
} | ||
|
||
func TestCreateMetricsExporter(t *testing.T) { | ||
factory := Factory{} | ||
|
||
exporter, err := factory.CreateMetricsExporter(zap.NewNop(), &Config{}) | ||
|
||
// unsupported | ||
assert.Nil(t, exporter) | ||
assert.Equal(t, configerror.ErrDataTypeIsNotSupported, err) | ||
} | ||
|
||
func TestCreateTraceExporterUsingSpecificTransportChannel(t *testing.T) { | ||
// mock transport channel creation | ||
factory := Factory{TransportChannel: &mockTransportChannel{}} | ||
exporter, err := factory.CreateTraceExporter(zap.NewNop(), factory.CreateDefaultConfig()) | ||
assert.NotNil(t, exporter) | ||
assert.Nil(t, err) | ||
} | ||
|
||
func TestCreateTraceExporterUsingDefaultTransportChannel(t *testing.T) { | ||
// We get the default transport channel creation, if we dont't specify one during factory creation | ||
factory := Factory{} | ||
assert.Nil(t, factory.TransportChannel) | ||
exporter, err := factory.CreateTraceExporter(zap.NewNop(), factory.CreateDefaultConfig()) | ||
assert.NotNil(t, exporter) | ||
assert.Nil(t, err) | ||
assert.NotNil(t, factory.TransportChannel) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
module azuremonitorexporter | ||
|
||
go 1.12 | ||
|
||
require ( | ||
cloud.google.com/go v0.45.1 // indirect | ||
code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c // indirect | ||
github.com/Microsoft/ApplicationInsights-Go v0.4.2 | ||
github.com/aws/aws-sdk-go v1.23.20 // indirect | ||
github.com/census-instrumentation/opencensus-proto v0.2.1 | ||
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 // indirect | ||
github.com/golang/protobuf v1.3.2 | ||
github.com/open-telemetry/opentelemetry-collector v0.2.1-0.20191016224815-dfabfb0c1d1e | ||
github.com/satori/go.uuid v1.2.0 // indirect | ||
github.com/stretchr/testify v1.4.0 | ||
github.com/tedsuo/ifrit v0.0.0-20191009134036-9a97d0632f00 // indirect | ||
go.opencensus.io v0.22.2 // indirect | ||
go.uber.org/multierr v1.4.0 // indirect | ||
go.uber.org/zap v1.13.0 | ||
golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914 // indirect | ||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect | ||
golang.org/x/sys v0.0.0-20191119195528-f068ffe820e4 // indirect | ||
golang.org/x/tools v0.0.0-20191119175705-11e13f1c3fd7 // indirect | ||
google.golang.org/appengine v1.6.2 // indirect | ||
google.golang.org/genproto v0.0.0-20191115221424-83cc0476cb11 // indirect | ||
google.golang.org/grpc v1.25.1 | ||
) |
Oops, something went wrong.