diff --git a/Makefile b/Makefile index a8e85258..8811c14e 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,13 @@ init: dart pub get # Generate mocks for unit tests. For config, see build.yaml. dart run build_runner build --delete-conflicting-outputs - dart pub global activate protoc_plugin 21.1.2 + if dart --version | grep 'Dart SDK version: 2'; then \ + dart pub global activate protoc_plugin 20.0.1; \ + else \ + dart pub global activate protoc_plugin 21.1.2; \ + fi cd lib/src/sdk/proto && \ - protoc --proto_path opentelemetry-proto --dart_out . \ + protoc --proto_path opentelemetry-proto --dart_out grpc:. \ opentelemetry-proto/opentelemetry/proto/common/v1/common.proto \ opentelemetry-proto/opentelemetry/proto/collector/trace/v1/trace_service.proto \ opentelemetry-proto/opentelemetry/proto/trace/v1/trace.proto \ diff --git a/README.md b/README.md index 0412444c..59e54efb 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,8 @@ import 'package:opentelemetry/sdk.dart' as otel_sdk; final exporter = otel_sdk.CollectorExporter(Uri.parse('https://my-collector.com/v1/traces')); ``` +The CollectorExporter supports transport protocols including `http/protobuf` and `grpc`. The default protocol is `http/protobuf`. + #### ConsoleExporter The ConsoleExporter has no requirements, and has no configuration options. @@ -190,6 +192,7 @@ const result = doWork(); ``` You can also create Span Events with additional Attributes: + ```dart span.addEvent('some log', attributes: { 'log.severity': 'error', @@ -203,6 +206,7 @@ span.addEvent('some log', attributes: { In order to generate protobuf definitions, you must have [protoc](https://github.com/protocolbuffers/protobuf/releases) installed and available in your path. ### Publishing New Versions -See https://github.com/Workiva/Observability/blob/master/doc/publishing_opentelemetry_dart.md + +See Only Workiva maintainers can publish new versions of opentelemetry-dart. diff --git a/lib/sdk.dart b/lib/sdk.dart index 3e94fa4a..77ff0eed 100644 --- a/lib/sdk.dart +++ b/lib/sdk.dart @@ -9,7 +9,8 @@ export 'src/sdk/time_providers/datetime_time_provider.dart' show DateTimeTimeProvider; export 'src/sdk/time_providers/time_provider.dart' show TimeProvider; export 'src/sdk/trace/exporters/span_exporter.dart' show SpanExporter; -export 'src/sdk/trace/exporters/collector_exporter.dart' show CollectorExporter; +export 'src/sdk/trace/exporters/collector_exporter.dart' + show CollectorExporter, CollectorExporterProtocol; export 'src/sdk/trace/exporters/console_exporter.dart' show ConsoleExporter; export 'src/sdk/trace/id_generator.dart' show IdGenerator; export 'src/sdk/trace/sampling/always_off_sampler.dart' show AlwaysOffSampler; diff --git a/lib/src/sdk/proto/opentelemetry/proto/collector/trace/v1/trace_service.pb.dart b/lib/src/sdk/proto/opentelemetry/proto/collector/trace/v1/trace_service.pb.dart index 8555bf73..b8aad146 100644 --- a/lib/src/sdk/proto/opentelemetry/proto/collector/trace/v1/trace_service.pb.dart +++ b/lib/src/sdk/proto/opentelemetry/proto/collector/trace/v1/trace_service.pb.dart @@ -12,17 +12,16 @@ // ignore_for_file: non_constant_identifier_names, prefer_final_fields // ignore_for_file: unnecessary_import, unnecessary_this, unused_import -import 'dart:async' as $async; import 'dart:core' as $core; import 'package:fixnum/fixnum.dart' as $fixnum; import 'package:protobuf/protobuf.dart' as $pb; -import '../../../trace/v1/trace.pb.dart' as $2; +import '../../../trace/v1/trace.pb.dart' as $3; class ExportTraceServiceRequest extends $pb.GeneratedMessage { factory ExportTraceServiceRequest({ - $core.Iterable<$2.ResourceSpans>? resourceSpans, + $core.Iterable<$3.ResourceSpans>? resourceSpans, }) { final $result = create(); if (resourceSpans != null) { @@ -35,7 +34,7 @@ class ExportTraceServiceRequest extends $pb.GeneratedMessage { factory ExportTraceServiceRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ExportTraceServiceRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'opentelemetry.proto.collector.trace.v1'), createEmptyInstance: create) - ..pc<$2.ResourceSpans>(1, _omitFieldNames ? '' : 'resourceSpans', $pb.PbFieldType.PM, subBuilder: $2.ResourceSpans.create) + ..pc<$3.ResourceSpans>(1, _omitFieldNames ? '' : 'resourceSpans', $pb.PbFieldType.PM, subBuilder: $3.ResourceSpans.create) ..hasRequiredFields = false ; @@ -66,7 +65,7 @@ class ExportTraceServiceRequest extends $pb.GeneratedMessage { /// data from multiple origins typically batch the data before forwarding further and /// in that case this array will contain multiple elements. @$pb.TagNumber(1) - $core.List<$2.ResourceSpans> get resourceSpans => $_getList(0); + $core.List<$3.ResourceSpans> get resourceSpans => $_getList(0); } class ExportTraceServiceResponse extends $pb.GeneratedMessage { @@ -211,15 +210,6 @@ class ExportTracePartialSuccess extends $pb.GeneratedMessage { void clearErrorMessage() => clearField(2); } -class TraceServiceApi { - $pb.RpcClient _client; - TraceServiceApi(this._client); - - $async.Future export($pb.ClientContext? ctx, ExportTraceServiceRequest request) => - _client.invoke(ctx, 'TraceService', 'Export', request, ExportTraceServiceResponse()) - ; -} - const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/lib/src/sdk/proto/opentelemetry/proto/collector/trace/v1/trace_service.pbgrpc.dart b/lib/src/sdk/proto/opentelemetry/proto/collector/trace/v1/trace_service.pbgrpc.dart new file mode 100644 index 00000000..2d056bf2 --- /dev/null +++ b/lib/src/sdk/proto/opentelemetry/proto/collector/trace/v1/trace_service.pbgrpc.dart @@ -0,0 +1,62 @@ +// Copyright 2021-2022 Workiva. +// Licensed under the Apache License, Version 2.0. Please see https://github.com/Workiva/opentelemetry-dart/blob/master/LICENSE for more information + +// +// Generated code. Do not modify. +// source: opentelemetry/proto/collector/trace/v1/trace_service.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +import 'dart:async' as $async; +import 'dart:core' as $core; + +import 'package:grpc/service_api.dart' as $grpc; +import 'package:protobuf/protobuf.dart' as $pb; + +import 'trace_service.pb.dart' as $0; + +export 'trace_service.pb.dart'; + +@$pb.GrpcServiceName('opentelemetry.proto.collector.trace.v1.TraceService') +class TraceServiceClient extends $grpc.Client { + static final _$export = $grpc.ClientMethod<$0.ExportTraceServiceRequest, $0.ExportTraceServiceResponse>( + '/opentelemetry.proto.collector.trace.v1.TraceService/Export', + ($0.ExportTraceServiceRequest value) => value.writeToBuffer(), + ($core.List<$core.int> value) => $0.ExportTraceServiceResponse.fromBuffer(value)); + + TraceServiceClient($grpc.ClientChannel channel, + {$grpc.CallOptions? options, + $core.Iterable<$grpc.ClientInterceptor>? interceptors}) + : super(channel, options: options, + interceptors: interceptors); + + $grpc.ResponseFuture<$0.ExportTraceServiceResponse> export($0.ExportTraceServiceRequest request, {$grpc.CallOptions? options}) { + return $createUnaryCall(_$export, request, options: options); + } +} + +@$pb.GrpcServiceName('opentelemetry.proto.collector.trace.v1.TraceService') +abstract class TraceServiceBase extends $grpc.Service { + $core.String get $name => 'opentelemetry.proto.collector.trace.v1.TraceService'; + + TraceServiceBase() { + $addMethod($grpc.ServiceMethod<$0.ExportTraceServiceRequest, $0.ExportTraceServiceResponse>( + 'Export', + export_Pre, + false, + false, + ($core.List<$core.int> value) => $0.ExportTraceServiceRequest.fromBuffer(value), + ($0.ExportTraceServiceResponse value) => value.writeToBuffer())); + } + + $async.Future<$0.ExportTraceServiceResponse> export_Pre($grpc.ServiceCall call, $async.Future<$0.ExportTraceServiceRequest> request) async { + return export(call, await request); + } + + $async.Future<$0.ExportTraceServiceResponse> export($grpc.ServiceCall call, $0.ExportTraceServiceRequest request); +} diff --git a/lib/src/sdk/proto/opentelemetry/proto/collector/trace/v1/trace_service.pbjson.dart b/lib/src/sdk/proto/opentelemetry/proto/collector/trace/v1/trace_service.pbjson.dart index f2766c20..1e5ae216 100644 --- a/lib/src/sdk/proto/opentelemetry/proto/collector/trace/v1/trace_service.pbjson.dart +++ b/lib/src/sdk/proto/opentelemetry/proto/collector/trace/v1/trace_service.pbjson.dart @@ -16,10 +16,6 @@ import 'dart:convert' as $convert; import 'dart:core' as $core; import 'dart:typed_data' as $typed_data; -import '../../../common/v1/common.pbjson.dart' as $0; -import '../../../resource/v1/resource.pbjson.dart' as $1; -import '../../../trace/v1/trace.pbjson.dart' as $2; - @$core.Deprecated('Use exportTraceServiceRequestDescriptor instead') const ExportTraceServiceRequest$json = { '1': 'ExportTraceServiceRequest', @@ -61,35 +57,3 @@ final $typed_data.Uint8List exportTracePartialSuccessDescriptor = $convert.base6 'ChlFeHBvcnRUcmFjZVBhcnRpYWxTdWNjZXNzEiUKDnJlamVjdGVkX3NwYW5zGAEgASgDUg1yZW' 'plY3RlZFNwYW5zEiMKDWVycm9yX21lc3NhZ2UYAiABKAlSDGVycm9yTWVzc2FnZQ=='); -const $core.Map<$core.String, $core.dynamic> TraceServiceBase$json = { - '1': 'TraceService', - '2': [ - {'1': 'Export', '2': '.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest', '3': '.opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse', '4': {}}, - ], -}; - -@$core.Deprecated('Use traceServiceDescriptor instead') -const $core.Map<$core.String, $core.Map<$core.String, $core.dynamic>> TraceServiceBase$messageJson = { - '.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest': ExportTraceServiceRequest$json, - '.opentelemetry.proto.trace.v1.ResourceSpans': $2.ResourceSpans$json, - '.opentelemetry.proto.resource.v1.Resource': $1.Resource$json, - '.opentelemetry.proto.common.v1.KeyValue': $0.KeyValue$json, - '.opentelemetry.proto.common.v1.AnyValue': $0.AnyValue$json, - '.opentelemetry.proto.common.v1.ArrayValue': $0.ArrayValue$json, - '.opentelemetry.proto.common.v1.KeyValueList': $0.KeyValueList$json, - '.opentelemetry.proto.trace.v1.ScopeSpans': $2.ScopeSpans$json, - '.opentelemetry.proto.common.v1.InstrumentationScope': $0.InstrumentationScope$json, - '.opentelemetry.proto.trace.v1.Span': $2.Span$json, - '.opentelemetry.proto.trace.v1.Span.Event': $2.Span_Event$json, - '.opentelemetry.proto.trace.v1.Span.Link': $2.Span_Link$json, - '.opentelemetry.proto.trace.v1.Status': $2.Status$json, - '.opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse': ExportTraceServiceResponse$json, - '.opentelemetry.proto.collector.trace.v1.ExportTracePartialSuccess': ExportTracePartialSuccess$json, -}; - -/// Descriptor for `TraceService`. Decode as a `google.protobuf.ServiceDescriptorProto`. -final $typed_data.Uint8List traceServiceDescriptor = $convert.base64Decode( - 'CgxUcmFjZVNlcnZpY2USkQEKBkV4cG9ydBJBLm9wZW50ZWxlbWV0cnkucHJvdG8uY29sbGVjdG' - '9yLnRyYWNlLnYxLkV4cG9ydFRyYWNlU2VydmljZVJlcXVlc3QaQi5vcGVudGVsZW1ldHJ5LnBy' - 'b3RvLmNvbGxlY3Rvci50cmFjZS52MS5FeHBvcnRUcmFjZVNlcnZpY2VSZXNwb25zZSIA'); - diff --git a/lib/src/sdk/proto/opentelemetry/proto/resource/v1/resource.pb.dart b/lib/src/sdk/proto/opentelemetry/proto/resource/v1/resource.pb.dart index 5013d4d8..df62baec 100644 --- a/lib/src/sdk/proto/opentelemetry/proto/resource/v1/resource.pb.dart +++ b/lib/src/sdk/proto/opentelemetry/proto/resource/v1/resource.pb.dart @@ -16,12 +16,12 @@ import 'dart:core' as $core; import 'package:protobuf/protobuf.dart' as $pb; -import '../../common/v1/common.pb.dart' as $0; +import '../../common/v1/common.pb.dart' as $1; /// Resource information. class Resource extends $pb.GeneratedMessage { factory Resource({ - $core.Iterable<$0.KeyValue>? attributes, + $core.Iterable<$1.KeyValue>? attributes, $core.int? droppedAttributesCount, }) { final $result = create(); @@ -38,7 +38,7 @@ class Resource extends $pb.GeneratedMessage { factory Resource.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Resource', package: const $pb.PackageName(_omitMessageNames ? '' : 'opentelemetry.proto.resource.v1'), createEmptyInstance: create) - ..pc<$0.KeyValue>(1, _omitFieldNames ? '' : 'attributes', $pb.PbFieldType.PM, subBuilder: $0.KeyValue.create) + ..pc<$1.KeyValue>(1, _omitFieldNames ? '' : 'attributes', $pb.PbFieldType.PM, subBuilder: $1.KeyValue.create) ..a<$core.int>(2, _omitFieldNames ? '' : 'droppedAttributesCount', $pb.PbFieldType.OU3) ..hasRequiredFields = false ; @@ -68,7 +68,7 @@ class Resource extends $pb.GeneratedMessage { /// Attribute keys MUST be unique (it is not allowed to have more than one /// attribute with the same key). @$pb.TagNumber(1) - $core.List<$0.KeyValue> get attributes => $_getList(0); + $core.List<$1.KeyValue> get attributes => $_getList(0); /// dropped_attributes_count is the number of dropped attributes. If the value is 0, then /// no attributes were dropped. diff --git a/lib/src/sdk/proto/opentelemetry/proto/trace/v1/trace.pb.dart b/lib/src/sdk/proto/opentelemetry/proto/trace/v1/trace.pb.dart index 83f26615..e46d7221 100644 --- a/lib/src/sdk/proto/opentelemetry/proto/trace/v1/trace.pb.dart +++ b/lib/src/sdk/proto/opentelemetry/proto/trace/v1/trace.pb.dart @@ -17,8 +17,8 @@ import 'dart:core' as $core; import 'package:fixnum/fixnum.dart' as $fixnum; import 'package:protobuf/protobuf.dart' as $pb; -import '../../common/v1/common.pb.dart' as $0; -import '../../resource/v1/resource.pb.dart' as $1; +import '../../common/v1/common.pb.dart' as $1; +import '../../resource/v1/resource.pb.dart' as $2; import 'trace.pbenum.dart'; export 'trace.pbenum.dart'; @@ -85,7 +85,7 @@ class TracesData extends $pb.GeneratedMessage { /// A collection of ScopeSpans from a Resource. class ResourceSpans extends $pb.GeneratedMessage { factory ResourceSpans({ - $1.Resource? resource, + $2.Resource? resource, $core.Iterable? scopeSpans, $core.String? schemaUrl, }) { @@ -106,7 +106,7 @@ class ResourceSpans extends $pb.GeneratedMessage { factory ResourceSpans.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ResourceSpans', package: const $pb.PackageName(_omitMessageNames ? '' : 'opentelemetry.proto.trace.v1'), createEmptyInstance: create) - ..aOM<$1.Resource>(1, _omitFieldNames ? '' : 'resource', subBuilder: $1.Resource.create) + ..aOM<$2.Resource>(1, _omitFieldNames ? '' : 'resource', subBuilder: $2.Resource.create) ..pc(2, _omitFieldNames ? '' : 'scopeSpans', $pb.PbFieldType.PM, subBuilder: ScopeSpans.create) ..aOS(3, _omitFieldNames ? '' : 'schemaUrl') ..hasRequiredFields = false @@ -136,15 +136,15 @@ class ResourceSpans extends $pb.GeneratedMessage { /// The resource for the spans in this message. /// If this field is not set then no resource info is known. @$pb.TagNumber(1) - $1.Resource get resource => $_getN(0); + $2.Resource get resource => $_getN(0); @$pb.TagNumber(1) - set resource($1.Resource v) { setField(1, v); } + set resource($2.Resource v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasResource() => $_has(0); @$pb.TagNumber(1) void clearResource() => clearField(1); @$pb.TagNumber(1) - $1.Resource ensureResource() => $_ensure(0); + $2.Resource ensureResource() => $_ensure(0); /// A list of ScopeSpans that originate from a resource. @$pb.TagNumber(2) @@ -168,7 +168,7 @@ class ResourceSpans extends $pb.GeneratedMessage { /// A collection of Spans produced by an InstrumentationScope. class ScopeSpans extends $pb.GeneratedMessage { factory ScopeSpans({ - $0.InstrumentationScope? scope, + $1.InstrumentationScope? scope, $core.Iterable? spans, $core.String? schemaUrl, }) { @@ -189,7 +189,7 @@ class ScopeSpans extends $pb.GeneratedMessage { factory ScopeSpans.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ScopeSpans', package: const $pb.PackageName(_omitMessageNames ? '' : 'opentelemetry.proto.trace.v1'), createEmptyInstance: create) - ..aOM<$0.InstrumentationScope>(1, _omitFieldNames ? '' : 'scope', subBuilder: $0.InstrumentationScope.create) + ..aOM<$1.InstrumentationScope>(1, _omitFieldNames ? '' : 'scope', subBuilder: $1.InstrumentationScope.create) ..pc(2, _omitFieldNames ? '' : 'spans', $pb.PbFieldType.PM, subBuilder: Span.create) ..aOS(3, _omitFieldNames ? '' : 'schemaUrl') ..hasRequiredFields = false @@ -220,15 +220,15 @@ class ScopeSpans extends $pb.GeneratedMessage { /// Semantically when InstrumentationScope isn't set, it is equivalent with /// an empty instrumentation scope name (unknown). @$pb.TagNumber(1) - $0.InstrumentationScope get scope => $_getN(0); + $1.InstrumentationScope get scope => $_getN(0); @$pb.TagNumber(1) - set scope($0.InstrumentationScope v) { setField(1, v); } + set scope($1.InstrumentationScope v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasScope() => $_has(0); @$pb.TagNumber(1) void clearScope() => clearField(1); @$pb.TagNumber(1) - $0.InstrumentationScope ensureScope() => $_ensure(0); + $1.InstrumentationScope ensureScope() => $_ensure(0); /// A list of Spans that originate from an instrumentation scope. @$pb.TagNumber(2) @@ -254,7 +254,7 @@ class Span_Event extends $pb.GeneratedMessage { factory Span_Event({ $fixnum.Int64? timeUnixNano, $core.String? name, - $core.Iterable<$0.KeyValue>? attributes, + $core.Iterable<$1.KeyValue>? attributes, $core.int? droppedAttributesCount, }) { final $result = create(); @@ -279,7 +279,7 @@ class Span_Event extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Span.Event', package: const $pb.PackageName(_omitMessageNames ? '' : 'opentelemetry.proto.trace.v1'), createEmptyInstance: create) ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'timeUnixNano', $pb.PbFieldType.OF6, defaultOrMaker: $fixnum.Int64.ZERO) ..aOS(2, _omitFieldNames ? '' : 'name') - ..pc<$0.KeyValue>(3, _omitFieldNames ? '' : 'attributes', $pb.PbFieldType.PM, subBuilder: $0.KeyValue.create) + ..pc<$1.KeyValue>(3, _omitFieldNames ? '' : 'attributes', $pb.PbFieldType.PM, subBuilder: $1.KeyValue.create) ..a<$core.int>(4, _omitFieldNames ? '' : 'droppedAttributesCount', $pb.PbFieldType.OU3) ..hasRequiredFields = false ; @@ -330,7 +330,7 @@ class Span_Event extends $pb.GeneratedMessage { /// Attribute keys MUST be unique (it is not allowed to have more than one /// attribute with the same key). @$pb.TagNumber(3) - $core.List<$0.KeyValue> get attributes => $_getList(2); + $core.List<$1.KeyValue> get attributes => $_getList(2); /// dropped_attributes_count is the number of dropped attributes. If the value is 0, /// then no attributes were dropped. @@ -353,7 +353,7 @@ class Span_Link extends $pb.GeneratedMessage { $core.List<$core.int>? traceId, $core.List<$core.int>? spanId, $core.String? traceState, - $core.Iterable<$0.KeyValue>? attributes, + $core.Iterable<$1.KeyValue>? attributes, $core.int? droppedAttributesCount, $core.int? flags, }) { @@ -386,7 +386,7 @@ class Span_Link extends $pb.GeneratedMessage { ..a<$core.List<$core.int>>(1, _omitFieldNames ? '' : 'traceId', $pb.PbFieldType.OY) ..a<$core.List<$core.int>>(2, _omitFieldNames ? '' : 'spanId', $pb.PbFieldType.OY) ..aOS(3, _omitFieldNames ? '' : 'traceState') - ..pc<$0.KeyValue>(4, _omitFieldNames ? '' : 'attributes', $pb.PbFieldType.PM, subBuilder: $0.KeyValue.create) + ..pc<$1.KeyValue>(4, _omitFieldNames ? '' : 'attributes', $pb.PbFieldType.PM, subBuilder: $1.KeyValue.create) ..a<$core.int>(5, _omitFieldNames ? '' : 'droppedAttributesCount', $pb.PbFieldType.OU3) ..a<$core.int>(6, _omitFieldNames ? '' : 'flags', $pb.PbFieldType.OF3) ..hasRequiredFields = false @@ -448,7 +448,7 @@ class Span_Link extends $pb.GeneratedMessage { /// Attribute keys MUST be unique (it is not allowed to have more than one /// attribute with the same key). @$pb.TagNumber(4) - $core.List<$0.KeyValue> get attributes => $_getList(3); + $core.List<$1.KeyValue> get attributes => $_getList(3); /// dropped_attributes_count is the number of dropped attributes. If the value is 0, /// then no attributes were dropped. @@ -492,7 +492,7 @@ class Span extends $pb.GeneratedMessage { Span_SpanKind? kind, $fixnum.Int64? startTimeUnixNano, $fixnum.Int64? endTimeUnixNano, - $core.Iterable<$0.KeyValue>? attributes, + $core.Iterable<$1.KeyValue>? attributes, $core.int? droppedAttributesCount, $core.Iterable? events, $core.int? droppedEventsCount, @@ -565,7 +565,7 @@ class Span extends $pb.GeneratedMessage { ..e(6, _omitFieldNames ? '' : 'kind', $pb.PbFieldType.OE, defaultOrMaker: Span_SpanKind.SPAN_KIND_UNSPECIFIED, valueOf: Span_SpanKind.valueOf, enumValues: Span_SpanKind.values) ..a<$fixnum.Int64>(7, _omitFieldNames ? '' : 'startTimeUnixNano', $pb.PbFieldType.OF6, defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(8, _omitFieldNames ? '' : 'endTimeUnixNano', $pb.PbFieldType.OF6, defaultOrMaker: $fixnum.Int64.ZERO) - ..pc<$0.KeyValue>(9, _omitFieldNames ? '' : 'attributes', $pb.PbFieldType.PM, subBuilder: $0.KeyValue.create) + ..pc<$1.KeyValue>(9, _omitFieldNames ? '' : 'attributes', $pb.PbFieldType.PM, subBuilder: $1.KeyValue.create) ..a<$core.int>(10, _omitFieldNames ? '' : 'droppedAttributesCount', $pb.PbFieldType.OU3) ..pc(11, _omitFieldNames ? '' : 'events', $pb.PbFieldType.PM, subBuilder: Span_Event.create) ..a<$core.int>(12, _omitFieldNames ? '' : 'droppedEventsCount', $pb.PbFieldType.OU3) @@ -725,7 +725,7 @@ class Span extends $pb.GeneratedMessage { /// Attribute keys MUST be unique (it is not allowed to have more than one /// attribute with the same key). @$pb.TagNumber(9) - $core.List<$0.KeyValue> get attributes => $_getList(8); + $core.List<$1.KeyValue> get attributes => $_getList(8); /// dropped_attributes_count is the number of attributes that were discarded. Attributes /// can be discarded because their keys are too long or because there are too many diff --git a/lib/src/sdk/trace/exporters/collector_exporter.dart b/lib/src/sdk/trace/exporters/collector_exporter.dart index 07f12ffd..2be6099d 100644 --- a/lib/src/sdk/trace/exporters/collector_exporter.dart +++ b/lib/src/sdk/trace/exporters/collector_exporter.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'package:fixnum/fixnum.dart'; import 'package:http/http.dart' as http; import 'package:logging/logging.dart'; +import 'package:grpc/grpc.dart'; import '../../../../api.dart' as api; import '../../../../sdk.dart' as sdk; @@ -15,18 +16,36 @@ import '../../proto/opentelemetry/proto/common/v1/common.pb.dart' as pb_common; import '../../proto/opentelemetry/proto/resource/v1/resource.pb.dart' as pb_resource; import '../../proto/opentelemetry/proto/trace/v1/trace.pb.dart' as pb_trace; +import '../../proto/opentelemetry/proto/collector/trace/v1/trace_service.pbgrpc.dart' + as pb_trace_service_grpc; + +enum CollectorExporterProtocol { httpProtobuf, gRPC } class CollectorExporter implements sdk.SpanExporter { final Logger _log = Logger('opentelemetry.CollectorExporter'); + final CollectorExporterProtocol protocol; final Uri uri; final http.Client client; final Map headers; var _isShutdown = false; + late pb_trace_service_grpc.TraceServiceClient _clientStub; - CollectorExporter(this.uri, - {http.Client? httpClient, this.headers = const {}}) - : client = httpClient ?? http.Client(); + CollectorExporter( + this.uri, { + http.Client? httpClient, + this.headers = const {}, + this.protocol = CollectorExporterProtocol.httpProtobuf, + }) : client = httpClient ?? http.Client() { + if (protocol == CollectorExporterProtocol.gRPC) { + _clientStub = pb_trace_service_grpc.TraceServiceClient( + ClientChannel( + uri.host, + port: uri.port, + ), + ); + } + } @override void export(List spans) { @@ -48,10 +67,24 @@ class CollectorExporter implements sdk.SpanExporter { try { final body = pb_trace_service.ExportTraceServiceRequest( resourceSpans: _spansToProtobuf(spans)); - final headers = {'Content-Type': 'application/x-protobuf'} - ..addAll(this.headers); - await client.post(uri, body: body.writeToBuffer(), headers: headers); + switch (protocol) { + case CollectorExporterProtocol.gRPC: + await _clientStub.export( + body, + options: CallOptions( + metadata: headers, + ), + ); + break; + + case CollectorExporterProtocol.httpProtobuf: + final headers = {'Content-Type': 'application/x-protobuf'} + ..addAll(this.headers); + + await client.post(uri, body: body.writeToBuffer(), headers: headers); + break; + } } catch (e) { _log.warning('Failed to export ${spans.length} spans.', e); } diff --git a/pubspec.yaml b/pubspec.yaml index 27bb8cc3..bb818248 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,14 +6,15 @@ environment: sdk: ">=2.19.0 <4.0.0" dependencies: - async: '>=2.5.0 <3.0.0' + async: ">=2.5.0 <3.0.0" collection: ^1.15.0 - fixnum: '>=1.0.0 <2.0.0' + fixnum: ">=1.0.0 <2.0.0" + grpc: ^3.1.0 http: ">=0.13.0 <2.0.0" logging: ^1.0.0 - meta: '>=1.6.0 <2.0.0' + meta: ">=1.6.0 <2.0.0" protobuf: ">=2.0.0 <4.0.0" - quiver: '>=3.0.0 <4.0.0' + quiver: ">=3.0.0 <4.0.0" dev_dependencies: build_runner: ^2.3.3 diff --git a/test/unit/mocks.dart b/test/unit/mocks.dart index 8c5919c2..37000188 100644 --- a/test/unit/mocks.dart +++ b/test/unit/mocks.dart @@ -9,9 +9,14 @@ import 'package:opentelemetry/src/sdk/trace/exporters/span_exporter.dart'; import 'package:opentelemetry/src/sdk/trace/read_only_span.dart'; import 'package:opentelemetry/src/sdk/trace/span_processors/span_processor.dart'; -class MockContext extends Mock implements Context{} -class MockHttpClient extends Mock implements http.Client{} -class MockSpan extends Mock implements Span{} -class MockReadOnlySpan extends Mock implements ReadOnlySpan{} -class MockSpanExporter extends Mock implements SpanExporter{} -class MockSpanProcessor extends Mock implements SpanProcessor{} +class MockContext extends Mock implements Context {} + +class MockHttpClient extends Mock implements http.Client {} + +class MockSpan extends Mock implements Span {} + +class MockReadOnlySpan extends Mock implements ReadOnlySpan {} + +class MockSpanExporter extends Mock implements SpanExporter {} + +class MockSpanProcessor extends Mock implements SpanProcessor {}