diff --git a/README.md b/README.md index ebd3b9a66..763ed861e 100644 --- a/README.md +++ b/README.md @@ -467,6 +467,7 @@ For documentation on the latest development code see the [documentation index][d * [nats](./plugins/outputs/nats) * [newrelic](./plugins/outputs/newrelic) * [nsq](./plugins/outputs/nsq) +* [opentelemetry](./plugins/outputs/opentelemetry) * [opentsdb](./plugins/outputs/opentsdb) * [prometheus](./plugins/outputs/prometheus_client) * [riemann](./plugins/outputs/riemann) diff --git a/docs/LICENSE_OF_DEPENDENCIES.md b/docs/LICENSE_OF_DEPENDENCIES.md index 7ae13c114..1ec09fe87 100644 --- a/docs/LICENSE_OF_DEPENDENCIES.md +++ b/docs/LICENSE_OF_DEPENDENCIES.md @@ -118,8 +118,8 @@ following works: - github.com/hashicorp/serf [Mozilla Public License 2.0](https://github.com/hashicorp/serf/blob/master/LICENSE) - github.com/influxdata/go-syslog [MIT License](https://github.com/influxdata/go-syslog/blob/develop/LICENSE) - github.com/influxdata/influxdb-observability/common [MIT License](https://github.com/influxdata/influxdb-observability/blob/main/LICENSE) +- github.com/influxdata/influxdb-observability/influx2otel [MIT License](https://github.com/influxdata/influxdb-observability/blob/main/LICENSE) - github.com/influxdata/influxdb-observability/otel2influx [MIT License](https://github.com/influxdata/influxdb-observability/blob/main/LICENSE) -- github.com/influxdata/influxdb-observability/otlp [MIT License](https://github.com/influxdata/influxdb-observability/blob/main/LICENSE) - github.com/influxdata/tail [MIT License](https://github.com/influxdata/tail/blob/master/LICENSE.txt) - github.com/influxdata/toml [MIT License](https://github.com/influxdata/toml/blob/master/LICENSE) - github.com/influxdata/wlog [MIT License](https://github.com/influxdata/wlog/blob/master/LICENSE) @@ -227,6 +227,7 @@ following works: - github.com/yuin/gopher-lua [MIT License](https://github.com/yuin/gopher-lua/blob/master/LICENSE) - go.mongodb.org/mongo-driver [Apache License 2.0](https://github.com/mongodb/mongo-go-driver/blob/master/LICENSE) - go.opencensus.io [Apache License 2.0](https://github.com/census-instrumentation/opencensus-go/blob/master/LICENSE) +- go.opentelemetry.io/collector/model [Apache License 2.0](https://github.com/open-telemetry/opentelemetry-collector/blob/main/LICENSE) - go.starlark.net [BSD 3-Clause "New" or "Revised" License](https://github.com/google/starlark-go/blob/master/LICENSE) - go.uber.org/atomic [MIT License](https://pkg.go.dev/go.uber.org/atomic?tab=licenses) - go.uber.org/multierr [MIT License](https://pkg.go.dev/go.uber.org/multierr?tab=licenses) diff --git a/go.mod b/go.mod index 8384ec47e..3cbedd836 100644 --- a/go.mod +++ b/go.mod @@ -64,7 +64,7 @@ require ( github.com/golang/geo v0.0.0-20190916061304-5b978397cfec github.com/golang/protobuf v1.5.2 github.com/golang/snappy v0.0.3 - github.com/google/go-cmp v0.5.5 + github.com/google/go-cmp v0.5.6 github.com/google/go-github/v32 v32.1.0 github.com/gopcua/opcua v0.1.13 github.com/gorilla/mux v1.7.3 @@ -76,9 +76,9 @@ require ( github.com/hashicorp/consul/api v1.9.1 github.com/hashicorp/go-msgpack v0.5.5 // indirect github.com/influxdata/go-syslog/v3 v3.0.0 - github.com/influxdata/influxdb-observability/common v0.0.0-20210429174543-86ae73cafd31 - github.com/influxdata/influxdb-observability/otel2influx v0.0.0-20210429174543-86ae73cafd31 - github.com/influxdata/influxdb-observability/otlp v0.0.0-20210429174543-86ae73cafd31 + github.com/influxdata/influxdb-observability/common v0.2.4 + github.com/influxdata/influxdb-observability/influx2otel v0.2.4 + github.com/influxdata/influxdb-observability/otel2influx v0.2.4 github.com/influxdata/tail v1.0.1-0.20210707231403-b283181d1fa7 github.com/influxdata/toml v0.0.0-20190415235208-270119a8ce65 github.com/influxdata/wlog v0.0.0-20160411224016-7c63b0a71ef8 @@ -137,10 +137,11 @@ require ( github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect github.com/yuin/gopher-lua v0.0.0-20180630135845-46796da1b0b4 // indirect go.mongodb.org/mongo-driver v1.5.3 + go.opentelemetry.io/collector/model v0.0.0-20210723184018-3b7d6ce4830c go.starlark.net v0.0.0-20210406145628-7a1108eaa012 go.uber.org/multierr v1.6.0 // indirect golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 + golang.org/x/net v0.0.0-20210610132358-84b48f89b13b golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 @@ -148,9 +149,9 @@ require ( golang.org/x/tools v0.1.2 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200205215550-e35592f146e4 google.golang.org/api v0.29.0 - google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c - google.golang.org/grpc v1.38.0 - google.golang.org/protobuf v1.26.0 + google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08 + google.golang.org/grpc v1.39.0 + google.golang.org/protobuf v1.27.1 gopkg.in/djherbis/times.v1 v1.2.0 gopkg.in/fatih/pool.v2 v2.0.0 // indirect gopkg.in/gorethink/gorethink.v3 v3.0.5 diff --git a/go.sum b/go.sum index 5c6871c90..90806c204 100644 --- a/go.sum +++ b/go.sum @@ -318,6 +318,7 @@ github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= @@ -508,7 +509,9 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v0.0.0-20200808040245-162e5629780b/go.mod h1:NAJj0yf/KaRKURN6nyi7A9IZydMivZEm9oQLWNjfKDc= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -740,8 +743,9 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/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 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 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-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II= github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= @@ -875,14 +879,12 @@ github.com/influxdata/flux v0.65.0/go.mod h1:BwN2XG2lMszOoquQaFdPET8FRQfrXiZsWmc github.com/influxdata/go-syslog/v3 v3.0.0 h1:jichmjSZlYK0VMmlz+k4WeOQd7z745YLsvGMqwtYt4I= github.com/influxdata/go-syslog/v3 v3.0.0/go.mod h1:tulsOp+CecTAYC27u9miMgq21GqXRW6VdKbOG+QSP4Q= github.com/influxdata/influxdb v1.8.2/go.mod h1:SIzcnsjaHRFpmlxpJ4S3NT64qtEKYweNTUMb/vh0OMQ= -github.com/influxdata/influxdb-observability/common v0.0.0-20210428231528-a010f53e3e02/go.mod h1:PMngVYsW4uwtzIVmj0ZfLL9UIOwo7Vs+09QHkoYMZv8= -github.com/influxdata/influxdb-observability/common v0.0.0-20210429174543-86ae73cafd31 h1:pfWcpiOrWLJvicIpCiFR8vqrkVbAuKUttWvQDmSlfUM= -github.com/influxdata/influxdb-observability/common v0.0.0-20210429174543-86ae73cafd31/go.mod h1:PMngVYsW4uwtzIVmj0ZfLL9UIOwo7Vs+09QHkoYMZv8= -github.com/influxdata/influxdb-observability/otel2influx v0.0.0-20210429174543-86ae73cafd31 h1:uiRNaaczvfx837c6OSH9Q6H4td1cWnR9X0pveHTHeYs= -github.com/influxdata/influxdb-observability/otel2influx v0.0.0-20210429174543-86ae73cafd31/go.mod h1:43guzIbK1oO/UMBuMCqG++LHZqLhMbWxqU4H1Lgpf28= -github.com/influxdata/influxdb-observability/otlp v0.0.0-20210428231528-a010f53e3e02/go.mod h1:J2N8KOAXSXgDhLjYWvjbxPhrgq3nVQ/npzW8l8T77Qo= -github.com/influxdata/influxdb-observability/otlp v0.0.0-20210429174543-86ae73cafd31 h1:Cf6WCNdgyxWv3x3uMehlexHAkWO3AZTAv5Q2yo0WQ0s= -github.com/influxdata/influxdb-observability/otlp v0.0.0-20210429174543-86ae73cafd31/go.mod h1:23SLY21Ag84PC0TbvVhdKoOVvrQF6nq5j5sFOW09ZBU= +github.com/influxdata/influxdb-observability/common v0.2.4 h1:GMycMMB0IMLzStLVgWIRJ4UFP5x5JOfITTRryL1dpgQ= +github.com/influxdata/influxdb-observability/common v0.2.4/go.mod h1:xbwEYfQLQIHnmcLQL8vniaZ1aEHI5D0K5Y6afiV5Wmo= +github.com/influxdata/influxdb-observability/influx2otel v0.2.4 h1:23qw/xv9ke6LIYo0/pNLhiS9bqlrkx2YiU3SNUKLxts= +github.com/influxdata/influxdb-observability/influx2otel v0.2.4/go.mod h1:WnBBHlTEB/orMD3io5TX8EZEnKryNviUbdlLhWwcqo0= +github.com/influxdata/influxdb-observability/otel2influx v0.2.4 h1:wDLEz/JxGXRJdmU9wT7YwslEaU6la27/Qs4f3a9VPhI= +github.com/influxdata/influxdb-observability/otel2influx v0.2.4/go.mod h1:HniEElFGVVs0KgHCjU/iIv6PFFvpicaLKd72PlCqn1o= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/influxql v1.1.0/go.mod h1:KpVI7okXjK6PRi3Z5B+mtKZli+R1DnZgb3N+tzevNgo= github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= @@ -1172,7 +1174,6 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/newrelic/newrelic-telemetry-sdk-go v0.5.1 h1:9YEHXplqlVkOltThchh+RxeODvTb1TBvQ1181aXg3pY= github.com/newrelic/newrelic-telemetry-sdk-go v0.5.1/go.mod h1:2kY6OeOxrJ+RIQlVjWDc/pZlT3MIf30prs6drzMfJ6E= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= github.com/nsqio/go-nsq v1.0.8 h1:3L2F8tNLlwXXlp2slDUrUWSBn2O3nMh8R1/KEDFTHPk= @@ -1566,6 +1567,9 @@ 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 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opentelemetry.io/collector/model v0.0.0-20210723184018-3b7d6ce4830c h1:3s2a2cav7u4W1b0cOYxmlj1y1NcVuDZwgUaAQ6wfImo= +go.opentelemetry.io/collector/model v0.0.0-20210723184018-3b7d6ce4830c/go.mod h1:PcHNnM+RUl0uD8VkSn93PO78N7kQYhfqpI/eki57pl4= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.starlark.net v0.0.0-20210406145628-7a1108eaa012 h1:4RGobP/iq7S22H0Bb92OEt+M8/cfBQnW+T+a2MC0sQo= go.starlark.net v0.0.0-20210406145628-7a1108eaa012/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1717,8 +1721,10 @@ golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b h1:k+E048sYJHyVnsr1GDrRZWQ32D2C7lWs9JRc0bel53A= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1837,7 +1843,10 @@ golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/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-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1997,8 +2006,9 @@ google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200815001618-f69a88009b70/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08 h1:pc16UedxnxXXtGxHCSUhafAoVHQZ0yXl8ZelMH4EETc= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -2019,9 +2029,11 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -2034,8 +2046,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM= @@ -2046,8 +2059,9 @@ gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/djherbis/times.v1 v1.2.0 h1:UCvDKl1L/fmBygl2Y7hubXCnY7t4Yj46ZrBFNUipFbM= gopkg.in/djherbis/times.v1 v1.2.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8= @@ -2107,8 +2121,9 @@ 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-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/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= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= diff --git a/plugins/inputs/opentelemetry/README.md b/plugins/inputs/opentelemetry/README.md index 9cb8f96eb..20cc36d5d 100644 --- a/plugins/inputs/opentelemetry/README.md +++ b/plugins/inputs/opentelemetry/README.md @@ -6,16 +6,28 @@ This plugin receives traces, metrics and logs from [OpenTelemetry](https://opent ```toml [[inputs.opentelemetry]] - ## Override the OpenTelemetry gRPC service address:port + ## Override the default (0.0.0.0:4317) destination OpenTelemetry gRPC service + ## address:port # service_address = "0.0.0.0:4317" - - ## Override the default request timeout + + ## Override the default (5s) new connection timeout # timeout = "5s" - - ## Select a schema for metrics: "prometheus-v1" or "prometheus-v2" + + ## Override the default (prometheus-v1) metrics schema. + ## Supports: "prometheus-v1", "prometheus-v2" ## For more information about the alternatives, read the Prometheus input ## plugin notes. # metrics_schema = "prometheus-v1" + + ## Optional TLS Config. + ## For advanced options: https://github.com/influxdata/telegraf/blob/v1.18.3/docs/TLS.md + ## + ## Set one or more allowed client CA certificate file names to + ## enable mutually authenticated TLS connections. + # tls_allowed_cacerts = ["/etc/telegraf/clientca.pem"] + ## Add service certificate and key. + # tls_cert = "/etc/telegraf/cert.pem" + # tls_key = "/etc/telegraf/key.pem" ``` #### Schema @@ -31,6 +43,8 @@ For metrics, two output schemata exist. Metrics received with `metrics_schema=prometheus-v1` are assigned measurement from the OTel field `Metric.name`. Metrics received with `metrics_schema=prometheus-v2` are stored in measurement `prometheus`. +Also see the OpenTelemetry output plugin for Telegraf. + ### Example Output #### Tracing Spans diff --git a/plugins/inputs/opentelemetry/grpc_services.go b/plugins/inputs/opentelemetry/grpc_services.go index 4045f8b60..f5fa450fa 100644 --- a/plugins/inputs/opentelemetry/grpc_services.go +++ b/plugins/inputs/opentelemetry/grpc_services.go @@ -6,14 +6,11 @@ import ( "github.com/influxdata/influxdb-observability/common" "github.com/influxdata/influxdb-observability/otel2influx" - otlpcollectorlogs "github.com/influxdata/influxdb-observability/otlp/collector/logs/v1" - otlpcollectormetrics "github.com/influxdata/influxdb-observability/otlp/collector/metrics/v1" - otlpcollectortrace "github.com/influxdata/influxdb-observability/otlp/collector/trace/v1" + "go.opentelemetry.io/collector/model/otlpgrpc" + "go.opentelemetry.io/collector/model/pdata" ) type traceService struct { - otlpcollectortrace.UnimplementedTraceServiceServer - converter *otel2influx.OtelTracesToLineProtocol writer *writeToAccumulator } @@ -26,24 +23,19 @@ func newTraceService(logger common.Logger, writer *writeToAccumulator) *traceSer } } -func (s *traceService) Export(ctx context.Context, req *otlpcollectortrace.ExportTraceServiceRequest) (*otlpcollectortrace.ExportTraceServiceResponse, error) { - err := s.converter.WriteTraces(ctx, req.ResourceSpans, s.writer) - if err != nil { - return nil, err - } - return &otlpcollectortrace.ExportTraceServiceResponse{}, nil +func (s *traceService) Export(ctx context.Context, req pdata.Traces) (otlpgrpc.TracesResponse, error) { + err := s.converter.WriteTraces(ctx, req, s.writer) + return otlpgrpc.NewTracesResponse(), err } type metricsService struct { - otlpcollectormetrics.UnimplementedMetricsServiceServer - converter *otel2influx.OtelMetricsToLineProtocol writer *writeToAccumulator } -var metricsSchemata = map[string]otel2influx.MetricsSchema{ - "prometheus-v1": otel2influx.MetricsSchemaTelegrafPrometheusV1, - "prometheus-v2": otel2influx.MetricsSchemaTelegrafPrometheusV2, +var metricsSchemata = map[string]common.MetricsSchema{ + "prometheus-v1": common.MetricsSchemaTelegrafPrometheusV1, + "prometheus-v2": common.MetricsSchemaTelegrafPrometheusV2, } func newMetricsService(logger common.Logger, writer *writeToAccumulator, schema string) (*metricsService, error) { @@ -62,17 +54,12 @@ func newMetricsService(logger common.Logger, writer *writeToAccumulator, schema }, nil } -func (s *metricsService) Export(ctx context.Context, req *otlpcollectormetrics.ExportMetricsServiceRequest) (*otlpcollectormetrics.ExportMetricsServiceResponse, error) { - err := s.converter.WriteMetrics(ctx, req.ResourceMetrics, s.writer) - if err != nil { - return nil, err - } - return &otlpcollectormetrics.ExportMetricsServiceResponse{}, nil +func (s *metricsService) Export(ctx context.Context, req pdata.Metrics) (otlpgrpc.MetricsResponse, error) { + err := s.converter.WriteMetrics(ctx, req, s.writer) + return otlpgrpc.MetricsResponse{}, err } type logsService struct { - otlpcollectorlogs.UnimplementedLogsServiceServer - converter *otel2influx.OtelLogsToLineProtocol writer *writeToAccumulator } @@ -85,10 +72,7 @@ func newLogsService(logger common.Logger, writer *writeToAccumulator) *logsServi } } -func (s *logsService) Export(ctx context.Context, req *otlpcollectorlogs.ExportLogsServiceRequest) (*otlpcollectorlogs.ExportLogsServiceResponse, error) { - err := s.converter.WriteLogs(ctx, req.ResourceLogs, s.writer) - if err != nil { - return nil, err - } - return &otlpcollectorlogs.ExportLogsServiceResponse{}, nil +func (s *logsService) Export(ctx context.Context, req pdata.Logs) (otlpgrpc.LogsResponse, error) { + err := s.converter.WriteLogs(ctx, req, s.writer) + return otlpgrpc.NewLogsResponse(), err } diff --git a/plugins/inputs/opentelemetry/opentelemetry.go b/plugins/inputs/opentelemetry/opentelemetry.go index cf2f6de08..2e6cbf9b8 100644 --- a/plugins/inputs/opentelemetry/opentelemetry.go +++ b/plugins/inputs/opentelemetry/opentelemetry.go @@ -6,20 +6,21 @@ import ( "sync" "time" - otlpcollectorlogs "github.com/influxdata/influxdb-observability/otlp/collector/logs/v1" - otlpcollectormetrics "github.com/influxdata/influxdb-observability/otlp/collector/metrics/v1" - otlpcollectortrace "github.com/influxdata/influxdb-observability/otlp/collector/trace/v1" "github.com/influxdata/telegraf" "github.com/influxdata/telegraf/config" + "github.com/influxdata/telegraf/plugins/common/tls" "github.com/influxdata/telegraf/plugins/inputs" + "go.opentelemetry.io/collector/model/otlpgrpc" "google.golang.org/grpc" + "google.golang.org/grpc/credentials" ) type OpenTelemetry struct { - ServiceAddress string `toml:"service_address"` - Timeout config.Duration `toml:"timeout"` + ServiceAddress string `toml:"service_address"` + MetricsSchema string `toml:"metrics_schema"` - MetricsSchema string `toml:"metrics_schema"` + tls.ServerConfig + Timeout config.Duration `toml:"timeout"` Log telegraf.Logger `toml:"-"` @@ -29,16 +30,28 @@ type OpenTelemetry struct { } const sampleConfig = ` - ## Override the OpenTelemetry gRPC service address:port + ## Override the default (0.0.0.0:4317) destination OpenTelemetry gRPC service + ## address:port # service_address = "0.0.0.0:4317" - ## Override the default request timeout + ## Override the default (5s) new connection timeout # timeout = "5s" - ## Select a schema for metrics: prometheus-v1 or prometheus-v2 + ## Override the default (prometheus-v1) metrics schema. + ## Supports: "prometheus-v1", "prometheus-v2" ## For more information about the alternatives, read the Prometheus input ## plugin notes. # metrics_schema = "prometheus-v1" + + ## Optional TLS Config. + ## For advanced options: https://github.com/influxdata/telegraf/blob/v1.18.3/docs/TLS.md + ## + ## Set one or more allowed client CA certificate file names to + ## enable mutually authenticated TLS connections. + # tls_allowed_cacerts = ["/etc/telegraf/clientca.pem"] + ## Add service certificate and key. + # tls_cert = "/etc/telegraf/cert.pem" + # tls_key = "/etc/telegraf/key.pem" ` func (o *OpenTelemetry) SampleConfig() string { @@ -54,22 +67,32 @@ func (o *OpenTelemetry) Gather(_ telegraf.Accumulator) error { } func (o *OpenTelemetry) Start(accumulator telegraf.Accumulator) error { - listener, err := net.Listen("tcp", o.ServiceAddress) - if err != nil { + var grpcOptions []grpc.ServerOption + if tlsConfig, err := o.ServerConfig.TLSConfig(); err != nil { return err + } else if tlsConfig != nil { + grpcOptions = append(grpcOptions, grpc.Creds(credentials.NewTLS(tlsConfig))) + } + if o.Timeout > 0 { + grpcOptions = append(grpcOptions, grpc.ConnectionTimeout(time.Duration(o.Timeout))) } logger := &otelLogger{o.Log} influxWriter := &writeToAccumulator{accumulator} - o.grpcServer = grpc.NewServer() + o.grpcServer = grpc.NewServer(grpcOptions...) - otlpcollectortrace.RegisterTraceServiceServer(o.grpcServer, newTraceService(logger, influxWriter)) + otlpgrpc.RegisterTracesServer(o.grpcServer, newTraceService(logger, influxWriter)) ms, err := newMetricsService(logger, influxWriter, o.MetricsSchema) if err != nil { return err } - otlpcollectormetrics.RegisterMetricsServiceServer(o.grpcServer, ms) - otlpcollectorlogs.RegisterLogsServiceServer(o.grpcServer, newLogsService(logger, influxWriter)) + otlpgrpc.RegisterMetricsServer(o.grpcServer, ms) + otlpgrpc.RegisterLogsServer(o.grpcServer, newLogsService(logger, influxWriter)) + + listener, err := net.Listen("tcp", o.ServiceAddress) + if err != nil { + return err + } o.wg.Add(1) go func() { @@ -94,8 +117,8 @@ func init() { inputs.Add("opentelemetry", func() telegraf.Input { return &OpenTelemetry{ ServiceAddress: "0.0.0.0:4317", - Timeout: config.Duration(5 * time.Second), MetricsSchema: "prometheus-v1", + Timeout: config.Duration(5 * time.Second), } }) } diff --git a/plugins/inputs/opentelemetry/writer.go b/plugins/inputs/opentelemetry/writer.go index 69b627e38..58906e62a 100644 --- a/plugins/inputs/opentelemetry/writer.go +++ b/plugins/inputs/opentelemetry/writer.go @@ -5,7 +5,7 @@ import ( "fmt" "time" - "github.com/influxdata/influxdb-observability/otel2influx" + "github.com/influxdata/influxdb-observability/common" "github.com/influxdata/telegraf" ) @@ -13,20 +13,20 @@ type writeToAccumulator struct { accumulator telegraf.Accumulator } -func (w *writeToAccumulator) WritePoint(_ context.Context, measurement string, tags map[string]string, fields map[string]interface{}, ts time.Time, vType otel2influx.InfluxWriterValueType) error { +func (w *writeToAccumulator) WritePoint(_ context.Context, measurement string, tags map[string]string, fields map[string]interface{}, ts time.Time, vType common.InfluxMetricValueType) error { switch vType { - case otel2influx.InfluxWriterValueTypeUntyped: + case common.InfluxMetricValueTypeUntyped: w.accumulator.AddFields(measurement, fields, tags, ts) - case otel2influx.InfluxWriterValueTypeGauge: + case common.InfluxMetricValueTypeGauge: w.accumulator.AddGauge(measurement, fields, tags, ts) - case otel2influx.InfluxWriterValueTypeSum: + case common.InfluxMetricValueTypeSum: w.accumulator.AddCounter(measurement, fields, tags, ts) - case otel2influx.InfluxWriterValueTypeHistogram: + case common.InfluxMetricValueTypeHistogram: w.accumulator.AddHistogram(measurement, fields, tags, ts) - case otel2influx.InfluxWriterValueTypeSummary: + case common.InfluxMetricValueTypeSummary: w.accumulator.AddSummary(measurement, fields, tags, ts) default: - return fmt.Errorf("unrecognized InfluxWriterValueType %q", vType) + return fmt.Errorf("unrecognized InfluxMetricValueType %q", vType) } return nil } diff --git a/plugins/outputs/all/all.go b/plugins/outputs/all/all.go index 1bda2a78c..7248b4ddc 100644 --- a/plugins/outputs/all/all.go +++ b/plugins/outputs/all/all.go @@ -34,6 +34,7 @@ import ( _ "github.com/influxdata/telegraf/plugins/outputs/nats" _ "github.com/influxdata/telegraf/plugins/outputs/newrelic" _ "github.com/influxdata/telegraf/plugins/outputs/nsq" + _ "github.com/influxdata/telegraf/plugins/outputs/opentelemetry" _ "github.com/influxdata/telegraf/plugins/outputs/opentsdb" _ "github.com/influxdata/telegraf/plugins/outputs/prometheus_client" _ "github.com/influxdata/telegraf/plugins/outputs/riemann" diff --git a/plugins/outputs/opentelemetry/README.md b/plugins/outputs/opentelemetry/README.md new file mode 100644 index 000000000..e6b4ebdfc --- /dev/null +++ b/plugins/outputs/opentelemetry/README.md @@ -0,0 +1,59 @@ +# OpenTelemetry Output Plugin + +This plugin sends metrics to [OpenTelemetry](https://opentelemetry.io) servers and agents via gRPC. + +### Configuration + +```toml +[[outputs.opentelemetry]] + ## Override the default (localhost:4317) OpenTelemetry gRPC service + ## address:port + # service_address = "localhost:4317" + + ## Override the default (5s) request timeout + # timeout = "5s" + + ## Optional TLS Config. + ## + ## Root certificates for verifying server certificates encoded in PEM format. + # tls_ca = "/etc/telegraf/ca.pem" + ## The public and private keypairs for the client encoded in PEM format. + ## May contain intermediate certificates. + # tls_cert = "/etc/telegraf/cert.pem" + # tls_key = "/etc/telegraf/key.pem" + ## Use TLS, but skip TLS chain and host verification. + # insecure_skip_verify = false + ## Send the specified TLS server name via SNI. + # tls_server_name = "foo.example.com" + + ## Override the default (gzip) compression used to send data. + ## Supports: "gzip", "none" + # compression = "gzip" + + ## Additional OpenTelemetry resource attributes + # [outputs.opentelemetry.attributes] + # "service.name" = "demo" + + ## Additional gRPC request metadata + # [outputs.opentelemetry.headers] + # key1 = "value1" +``` + +#### Schema + +The InfluxDB->OpenTelemetry conversion [schema](https://github.com/influxdata/influxdb-observability/blob/main/docs/index.md) +and [implementation](https://github.com/influxdata/influxdb-observability/tree/main/influx2otel) +are hosted at https://github.com/influxdata/influxdb-observability . + +For metrics, two input schemata exist. +Line protocol with measurement name `prometheus` is assumed to have a schema +matching [Prometheus input plugin](../../inputs/prometheus/README.md) when `metric_version = 2`. +Line protocol with other measurement names is assumed to have schema +matching [Prometheus input plugin](../../inputs/prometheus/README.md) when `metric_version = 1`. +If both schema assumptions fail, then the line protocol data is interpreted as: +- Metric type = gauge (or counter, if indicated by the input plugin) +- Metric name = `[measurement]_[field key]` +- Metric value = line protocol field value, cast to float +- Metric labels = line protocol tags + +Also see the [OpenTelemetry input plugin](../../inputs/opentelemetry/README.md). diff --git a/plugins/outputs/opentelemetry/logger.go b/plugins/outputs/opentelemetry/logger.go new file mode 100644 index 000000000..3db3621bc --- /dev/null +++ b/plugins/outputs/opentelemetry/logger.go @@ -0,0 +1,16 @@ +package opentelemetry + +import ( + "strings" + + "github.com/influxdata/telegraf" +) + +type otelLogger struct { + telegraf.Logger +} + +func (l otelLogger) Debug(msg string, kv ...interface{}) { + format := msg + strings.Repeat(" %s=%q", len(kv)/2) + l.Logger.Debugf(format, kv...) +} diff --git a/plugins/outputs/opentelemetry/opentelemetry.go b/plugins/outputs/opentelemetry/opentelemetry.go new file mode 100644 index 000000000..ea68fbae6 --- /dev/null +++ b/plugins/outputs/opentelemetry/opentelemetry.go @@ -0,0 +1,182 @@ +package opentelemetry + +import ( + "context" + "time" + + "github.com/influxdata/influxdb-observability/common" + "github.com/influxdata/influxdb-observability/influx2otel" + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/config" + "github.com/influxdata/telegraf/plugins/common/tls" + "github.com/influxdata/telegraf/plugins/outputs" + "go.opentelemetry.io/collector/model/otlpgrpc" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" +) + +type OpenTelemetry struct { + ServiceAddress string `toml:"service_address"` + + tls.ClientConfig + Timeout config.Duration `toml:"timeout"` + Compression string `toml:"compression"` + Headers map[string]string `toml:"headers"` + Attributes map[string]string `toml:"attributes"` + + Log telegraf.Logger `toml:"-"` + + metricsConverter *influx2otel.LineProtocolToOtelMetrics + grpcClientConn *grpc.ClientConn + metricsServiceClient otlpgrpc.MetricsClient + callOptions []grpc.CallOption +} + +const sampleConfig = ` + ## Override the default (localhost:4317) OpenTelemetry gRPC service + ## address:port + # service_address = "localhost:4317" + + ## Override the default (5s) request timeout + # timeout = "5s" + + ## Optional TLS Config. + ## + ## Root certificates for verifying server certificates encoded in PEM format. + # tls_ca = "/etc/telegraf/ca.pem" + ## The public and private keypairs for the client encoded in PEM format. + ## May contain intermediate certificates. + # tls_cert = "/etc/telegraf/cert.pem" + # tls_key = "/etc/telegraf/key.pem" + ## Use TLS, but skip TLS chain and host verification. + # insecure_skip_verify = false + ## Send the specified TLS server name via SNI. + # tls_server_name = "foo.example.com" + + ## Override the default (gzip) compression used to send data. + ## Supports: "gzip", "none" + # compression = "gzip" + + ## Additional OpenTelemetry resource attributes + # [outputs.opentelemetry.attributes] + # "service.name" = "demo" + + ## Additional gRPC request metadata + # [outputs.opentelemetry.headers] + # key1 = "value1" +` + +func (o *OpenTelemetry) SampleConfig() string { + return sampleConfig +} + +func (o *OpenTelemetry) Description() string { + return "Send OpenTelemetry metrics over gRPC" +} + +func (o *OpenTelemetry) Connect() error { + logger := &otelLogger{o.Log} + + if o.ServiceAddress == "" { + o.ServiceAddress = defaultServiceAddress + } + if o.Timeout <= 0 { + o.Timeout = defaultTimeout + } + if o.Compression == "" { + o.Compression = defaultCompression + } + + metricsConverter, err := influx2otel.NewLineProtocolToOtelMetrics(logger) + if err != nil { + return err + } + + var grpcTLSDialOption grpc.DialOption + if tlsConfig, err := o.ClientConfig.TLSConfig(); err != nil { + return err + } else if tlsConfig != nil { + grpcTLSDialOption = grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)) + } else { + grpcTLSDialOption = grpc.WithInsecure() + } + + grpcClientConn, err := grpc.Dial(o.ServiceAddress, grpcTLSDialOption) + if err != nil { + return err + } + + metricsServiceClient := otlpgrpc.NewMetricsClient(grpcClientConn) + + o.metricsConverter = metricsConverter + o.grpcClientConn = grpcClientConn + o.metricsServiceClient = metricsServiceClient + + if o.Compression != "" && o.Compression != "none" { + o.callOptions = append(o.callOptions, grpc.UseCompressor(o.Compression)) + } + + return nil +} + +func (o *OpenTelemetry) Close() error { + if o.grpcClientConn != nil { + err := o.grpcClientConn.Close() + o.grpcClientConn = nil + return err + } + return nil +} + +func (o *OpenTelemetry) Write(metrics []telegraf.Metric) error { + batch := o.metricsConverter.NewBatch() + for _, metric := range metrics { + var vType common.InfluxMetricValueType + switch metric.Type() { + case telegraf.Gauge: + vType = common.InfluxMetricValueTypeGauge + case telegraf.Untyped: + vType = common.InfluxMetricValueTypeUntyped + case telegraf.Counter: + vType = common.InfluxMetricValueTypeSum + case telegraf.Histogram: + vType = common.InfluxMetricValueTypeHistogram + case telegraf.Summary: + vType = common.InfluxMetricValueTypeSummary + default: + o.Log.Warnf("unrecognized metric type %Q", metric.Type()) + continue + } + err := batch.AddPoint(metric.Name(), metric.Tags(), metric.Fields(), metric.Time(), vType) + if err != nil { + o.Log.Warnf("failed to add point: %s", err) + continue + } + } + + md := batch.GetMetrics() + if md.ResourceMetrics().Len() == 0 { + return nil + } + + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(o.Timeout)) + defer cancel() + _, err := o.metricsServiceClient.Export(ctx, md, o.callOptions...) + return err +} + +const ( + defaultServiceAddress = "localhost:4317" + defaultTimeout = config.Duration(5 * time.Second) + defaultCompression = "gzip" +) + +func init() { + outputs.Add("opentelemetry", func() telegraf.Output { + return &OpenTelemetry{ + ServiceAddress: defaultServiceAddress, + Timeout: defaultTimeout, + Compression: defaultCompression, + } + }) +} diff --git a/plugins/outputs/opentelemetry/opentelemetry_test.go b/plugins/outputs/opentelemetry/opentelemetry_test.go new file mode 100644 index 000000000..b61f48097 --- /dev/null +++ b/plugins/outputs/opentelemetry/opentelemetry_test.go @@ -0,0 +1,135 @@ +package opentelemetry + +import ( + "context" + "net" + "strings" + "testing" + "time" + + "github.com/influxdata/influxdb-observability/common" + "github.com/influxdata/influxdb-observability/influx2otel" + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/config" + "github.com/influxdata/telegraf/testutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/model/otlp" + "go.opentelemetry.io/collector/model/otlpgrpc" + "go.opentelemetry.io/collector/model/pdata" + "google.golang.org/grpc" +) + +func TestOpenTelemetry(t *testing.T) { + expect := pdata.NewMetrics() + { + rm := expect.ResourceMetrics().AppendEmpty() + rm.Resource().Attributes().InsertString("host.name", "potato") + ilm := rm.InstrumentationLibraryMetrics().AppendEmpty() + ilm.InstrumentationLibrary().SetName("My Library Name") + m := ilm.Metrics().AppendEmpty() + m.SetName("cpu_temp") + m.SetDataType(pdata.MetricDataTypeGauge) + dp := m.Gauge().DataPoints().AppendEmpty() + dp.LabelsMap().Insert("foo", "bar") + dp.SetTimestamp(pdata.Timestamp(1622848686000000000)) + dp.SetValue(87.332) + } + m := newMockOtelService(t) + t.Cleanup(m.Cleanup) + + metricsConverter, err := influx2otel.NewLineProtocolToOtelMetrics(common.NoopLogger{}) + require.NoError(t, err) + plugin := &OpenTelemetry{ + ServiceAddress: m.Address(), + Timeout: config.Duration(time.Second), + metricsConverter: metricsConverter, + grpcClientConn: m.GrpcClient(), + metricsServiceClient: otlpgrpc.NewMetricsClient(m.GrpcClient()), + } + + input := testutil.MustMetric( + "cpu_temp", + map[string]string{ + "foo": "bar", + "otel.library.name": "My Library Name", + "host.name": "potato", + }, + map[string]interface{}{ + "gauge": 87.332, + }, + time.Unix(0, 1622848686000000000)) + + err = plugin.Write([]telegraf.Metric{input}) + if err != nil { + // TODO not sure why the service returns this error, but the data arrives as required by the test + // rpc error: code = Internal desc = grpc: error while marshaling: proto: Marshal called with nil + if !strings.Contains(err.Error(), "proto: Marshal called with nil") { + assert.NoError(t, err) + } + } + + got := m.GotMetrics() + + expectJSON, err := otlp.NewJSONMetricsMarshaler().MarshalMetrics(expect) + require.NoError(t, err) + + gotJSON, err := otlp.NewJSONMetricsMarshaler().MarshalMetrics(got) + require.NoError(t, err) + + assert.JSONEq(t, string(expectJSON), string(gotJSON)) +} + +var _ otlpgrpc.MetricsServer = (*mockOtelService)(nil) + +type mockOtelService struct { + t *testing.T + listener net.Listener + grpcServer *grpc.Server + grpcClient *grpc.ClientConn + + metrics pdata.Metrics +} + +func newMockOtelService(t *testing.T) *mockOtelService { + listener, err := net.Listen("tcp", "127.0.0.1:0") + require.NoError(t, err) + grpcServer := grpc.NewServer() + + mockOtelService := &mockOtelService{ + t: t, + listener: listener, + grpcServer: grpcServer, + } + + otlpgrpc.RegisterMetricsServer(grpcServer, mockOtelService) + go func() { assert.NoError(t, grpcServer.Serve(listener)) }() + + grpcClient, err := grpc.Dial(listener.Addr().String(), grpc.WithInsecure(), grpc.WithBlock()) + require.NoError(t, err) + mockOtelService.grpcClient = grpcClient + + return mockOtelService +} + +func (m *mockOtelService) Cleanup() { + assert.NoError(m.t, m.grpcClient.Close()) + m.grpcServer.Stop() +} + +func (m *mockOtelService) GrpcClient() *grpc.ClientConn { + return m.grpcClient +} + +func (m *mockOtelService) GotMetrics() pdata.Metrics { + return m.metrics +} + +func (m *mockOtelService) Address() string { + return m.listener.Addr().String() +} + +func (m *mockOtelService) Export(ctx context.Context, request pdata.Metrics) (otlpgrpc.MetricsResponse, error) { + m.metrics = request.Clone() + return otlpgrpc.MetricsResponse{}, nil +}