-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Restore jaegerthrifthttpexporter (#5666)
* Close #4667: Restore jaegerthrifthttpexporter In some cases, a Jaeger collector may be deployed to a platform that does not support gRPC. This restores the jaegerthrifthttpexporter so that OpenTelemetry users who need to ship traces to a Jaeger collector that cannot support gRPC are able to ship traces using the Jaeger collector's [Thrift over HTTP API](https://www.jaegertracing.io/docs/1.27/apis/#thrift-over-http-stable). * Add warning regarding usage of the Jaeger Thrift HTTP exporter * Update exporter/jaegerthrifthttpexporter/README.md Co-authored-by: Juraci Paixão Kröhling <[email protected]> * Bump go version * [WIP] Exporter refactor This removes the protospan_to_jaegerthrift translator because we can use the existing internal_to_jaegerproto translator to translate from from internal spans to Jaeger domain spans. The Jaeger domain spans to Jaeger Thrift conversion is small enough that I think it makes more sense as part of the exporter now. That said, some tests may need to be added for the exporter to cover the code that used to be in protospan_to_jaegerthrift. I still need to convert from jaeger/model.Batch to thrift-gen/jaeger.Batch, which will require a separate translator * Fix lint errors * Use HTTPClientSettings for configuration * Use same version as other exporters in go.mod * Update README to match new config requirements * Wrap all errors returned by pushTraceData with consumererror.NewPermanent * Include Jaeger Thrift exporter in exporters_test * Only return an error from start if there's an error * Fix exporters_test & error message, add exporter to versions.yaml Co-authored-by: Juraci Paixão Kröhling <[email protected]>
- Loading branch information
1 parent
1f4ab83
commit 8e5b3ac
Showing
21 changed files
with
2,163 additions
and
1 deletion.
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
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,37 @@ | ||
# Jaeger Thrift Exporter | ||
|
||
This exporter supports sending trace data to [Jaeger](https://www.jaegertracing.io) over Thrift HTTP. | ||
|
||
*WARNING:* The [Jaeger gRPC Exporter](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/jaegerexporter) is the recommended one for exporting traces from an OpenTelemetry Collector to Jaeger. This Jaeger Thrift Exporter should only be used to export traces to a Jaeger Collector that is unable to expose the [gRPC API](https://www.jaegertracing.io/docs/1.27/apis/#protobuf-via-grpc-stable). | ||
|
||
Supported pipeline types: traces | ||
|
||
## Configuration | ||
|
||
The following settings are required: | ||
|
||
- `endpoint` (no default): target to which the exporter is going to send Jaeger trace data, | ||
using the Thrift HTTP protocol. | ||
|
||
The following settings can be optionally configured: | ||
|
||
- `timeout` (default = 5s): the maximum time to wait for a HTTP request to complete | ||
- `headers` (no default): headers to be added to the HTTP request | ||
|
||
Example: | ||
|
||
```yaml | ||
exporters: | ||
jaeger_thrift: | ||
endpoint: "http://jaeger.example.com/api/traces" | ||
timeout: 2s | ||
headers: | ||
added-entry: "added value" | ||
dot.test: test | ||
``` | ||
The full list of settings exposed for this exporter are documented [here](config.go) | ||
with detailed sample configurations [here](testdata/config.yaml). | ||
This exporter also offers proxy support as documented | ||
[here](https://github.com/open-telemetry/opentelemetry-collector/tree/main/exporter#proxy-support). |
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,33 @@ | ||
// 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 jaegerthrifthttpexporter | ||
|
||
import ( | ||
"go.opentelemetry.io/collector/config" | ||
"go.opentelemetry.io/collector/config/confighttp" | ||
) | ||
|
||
// Config defines configuration for Jaeger Thrift over HTTP exporter. | ||
type Config struct { | ||
config.ExporterSettings `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct | ||
confighttp.HTTPClientSettings `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct. | ||
} | ||
|
||
var _ config.Exporter = (*Config)(nil) | ||
|
||
// Validate checks if the exporter configuration is valid | ||
func (cfg *Config) Validate() error { | ||
return nil | ||
} |
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,66 @@ | ||
// 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 jaegerthrifthttpexporter | ||
|
||
import ( | ||
"context" | ||
"path" | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"go.opentelemetry.io/collector/component/componenttest" | ||
"go.opentelemetry.io/collector/config" | ||
"go.opentelemetry.io/collector/config/confighttp" | ||
"go.opentelemetry.io/collector/config/configtest" | ||
) | ||
|
||
func TestLoadConfig(t *testing.T) { | ||
factories, err := componenttest.NopFactories() | ||
assert.Nil(t, err) | ||
|
||
factory := NewFactory() | ||
factories.Exporters[typeStr] = factory | ||
cfg, err := configtest.LoadConfigAndValidate(path.Join(".", "testdata", "config.yaml"), factories) | ||
|
||
require.NoError(t, err) | ||
require.NotNil(t, cfg) | ||
|
||
e0 := cfg.Exporters[config.NewComponentID(typeStr)] | ||
|
||
// URL doesn't have a default value so set it directly. | ||
defaultCfg := factory.CreateDefaultConfig().(*Config) | ||
defaultCfg.Endpoint = "http://jaeger.example:14268/api/traces" | ||
assert.Equal(t, defaultCfg, e0) | ||
|
||
e1 := cfg.Exporters[config.NewComponentIDWithName(typeStr, "2")] | ||
expectedCfg := Config{ | ||
ExporterSettings: config.NewExporterSettings(config.NewComponentIDWithName(typeStr, "2")), | ||
HTTPClientSettings: confighttp.HTTPClientSettings{ | ||
Endpoint: "http://jaeger.example.com/api/traces", | ||
Headers: map[string]string{ | ||
"added-entry": "added value", | ||
"dot.test": "test", | ||
}, | ||
Timeout: 2 * time.Second, | ||
}, | ||
} | ||
assert.Equal(t, &expectedCfg, e1) | ||
|
||
te, err := factory.CreateTracesExporter(context.Background(), componenttest.NewNopExporterCreateSettings(), e1) | ||
require.NoError(t, err) | ||
require.NotNil(t, te) | ||
} |
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,17 @@ | ||
// 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 jaegerthrifthttpexporter implements an exporter that sends trace data | ||
// to a Jaeger collector Thrift over HTTP endpoint. | ||
package jaegerthrifthttpexporter |
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,163 @@ | ||
// 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 jaegerthrifthttpexporter | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"fmt" | ||
"io" | ||
"io/ioutil" | ||
"net/http" | ||
|
||
"github.com/apache/thrift/lib/go/thrift" | ||
"github.com/jaegertracing/jaeger/model" | ||
jaegerThriftConverter "github.com/jaegertracing/jaeger/model/converter/thrift/jaeger" | ||
"github.com/jaegertracing/jaeger/thrift-gen/jaeger" | ||
"go.opentelemetry.io/collector/component" | ||
"go.opentelemetry.io/collector/consumer/consumererror" | ||
"go.opentelemetry.io/collector/exporter/exporterhelper" | ||
"go.opentelemetry.io/collector/model/pdata" | ||
|
||
jaegertranslator "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger" | ||
) | ||
|
||
func newTracesExporter( | ||
config *Config, | ||
params component.ExporterCreateSettings, | ||
) (component.TracesExporter, error) { | ||
s := &jaegerThriftHTTPSender{ | ||
config: config, | ||
} | ||
|
||
return exporterhelper.NewTracesExporter( | ||
config, | ||
params, | ||
s.pushTraceData, | ||
exporterhelper.WithStart(s.start), | ||
) | ||
} | ||
|
||
// jaegerThriftHTTPSender forwards spans encoded in the jaeger thrift | ||
// format to a http server. | ||
type jaegerThriftHTTPSender struct { | ||
config *Config | ||
client *http.Client | ||
} | ||
|
||
// start starts the exporter | ||
func (s *jaegerThriftHTTPSender) start(_ context.Context, host component.Host) (err error) { | ||
s.client, err = s.config.HTTPClientSettings.ToClient(host.GetExtensions()) | ||
|
||
if err != nil { | ||
return consumererror.NewPermanent(err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (s *jaegerThriftHTTPSender) pushTraceData( | ||
ctx context.Context, | ||
td pdata.Traces, | ||
) error { | ||
batches, err := jaegertranslator.InternalTracesToJaegerProto(td) | ||
if err != nil { | ||
return consumererror.NewPermanent(fmt.Errorf("failed to push trace data via Jaeger Thrift HTTP exporter: %w", err)) | ||
} | ||
|
||
for i := 0; i < len(batches); i++ { | ||
body, err := serializeThrift(ctx, batches[i]) | ||
if err != nil { | ||
return consumererror.NewPermanent(err) | ||
} | ||
|
||
req, err := http.NewRequest("POST", s.config.HTTPClientSettings.Endpoint, body) | ||
if err != nil { | ||
return consumererror.NewPermanent(err) | ||
} | ||
|
||
req.Header.Set("Content-Type", "application/x-thrift") | ||
|
||
resp, err := s.client.Do(req) | ||
if err != nil { | ||
return consumererror.NewPermanent(err) | ||
} | ||
|
||
io.Copy(ioutil.Discard, resp.Body) | ||
resp.Body.Close() | ||
|
||
if resp.StatusCode >= http.StatusBadRequest { | ||
err = fmt.Errorf( | ||
"HTTP %d %q", | ||
resp.StatusCode, | ||
http.StatusText(resp.StatusCode)) | ||
return consumererror.NewPermanent(err) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func serializeThrift(ctx context.Context, batch *model.Batch) (*bytes.Buffer, error) { | ||
thriftSpans := jaegerThriftConverter.FromDomain(batch.GetSpans()) | ||
thriftProcess := jaeger.Process{ | ||
ServiceName: batch.GetProcess().GetServiceName(), | ||
Tags: convertTagsToThrift(batch.GetProcess().GetTags()), | ||
} | ||
thriftBatch := jaeger.Batch{ | ||
Spans: thriftSpans, | ||
Process: &thriftProcess, | ||
} | ||
t := thrift.NewTMemoryBuffer() | ||
p := thrift.NewTBinaryProtocolConf(t, nil) | ||
if err := thriftBatch.Write(ctx, p); err != nil { | ||
return nil, err | ||
} | ||
return t.Buffer, nil | ||
} | ||
|
||
func convertTagsToThrift(tags []model.KeyValue) []*jaeger.Tag { | ||
thriftTags := make([]*jaeger.Tag, 0, len(tags)) | ||
|
||
for i := 0; i < len(tags); i++ { | ||
tag := tags[i] | ||
thriftTag := &jaeger.Tag{Key: tag.GetKey()} | ||
switch tag.GetVType() { | ||
case model.ValueType_STRING: | ||
str := tag.GetVStr() | ||
thriftTag.VStr = &str | ||
thriftTag.VType = jaeger.TagType_STRING | ||
case model.ValueType_INT64: | ||
i := tag.GetVInt64() | ||
thriftTag.VLong = &i | ||
thriftTag.VType = jaeger.TagType_LONG | ||
case model.ValueType_BOOL: | ||
b := tag.GetVBool() | ||
thriftTag.VBool = &b | ||
thriftTag.VType = jaeger.TagType_BOOL | ||
case model.ValueType_FLOAT64: | ||
d := tag.GetVFloat64() | ||
thriftTag.VDouble = &d | ||
thriftTag.VType = jaeger.TagType_DOUBLE | ||
default: | ||
str := "<Unknown tag type for key \"" + tag.GetKey() + "\">" | ||
thriftTag.VStr = &str | ||
thriftTag.VType = jaeger.TagType_STRING | ||
} | ||
thriftTags = append(thriftTags, thriftTag) | ||
} | ||
|
||
return thriftTags | ||
} |
Oops, something went wrong.