Skip to content

Commit 4c0f3f1

Browse files
authored
feat(sdk-node): set TracerProvider in startNodeSDK() (#6607)
1 parent 417f2f1 commit 4c0f3f1

12 files changed

Lines changed: 811 additions & 3 deletions

File tree

experimental/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2
1111
### :rocket: Features
1212

1313
* feat(sdk-node): wire attribute_keys from declarative configuration to ViewOptions.attributesProcessors [#6427](https://github.com/open-telemetry/opentelemetry-js/issues/6427) @ravitheja4531-cell
14+
* feat(sdk-node): set TracerProvider in startNodeSDK() [#6607](https://github.com/open-telemetry/opentelemetry-js/pull/6607) @maryliag
1415

1516
### :bug: Bug Fixes
1617

@@ -61,7 +62,7 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2
6162
* feat(configuration): add sampler configuration parsing support [#6409](https://github.com/open-telemetry/opentelemetry-js/pull/6409) @MikeGoldsmith
6263
* feat(configuration): add resource detection parsing [#6435](https://github.com/open-telemetry/opentelemetry-js/pull/6435) @MikeGoldsmith
6364
* feat(configuration): export interfaces required in other packages [#6462](https://github.com/open-telemetry/opentelemetry-js/pull/6462) @maryliag
64-
* feat(configuration): set MeterProvider on sdk start [#6463](https://github.com/open-telemetry/opentelemetry-js/pull/6463) @maryliag
65+
* feat(sdk-node): set MeterProvider in startNodeSDK() [#6463](https://github.com/open-telemetry/opentelemetry-js/pull/6463) @maryliag
6566
* feat(configuration): export interfaces required in other packages [#6507](https://github.com/open-telemetry/opentelemetry-js/pull/6507) @maryliag
6667
* feat(configuration): refactoring config loader to print warning message [#6524](https://github.com/open-telemetry/opentelemetry-js/pull/6524) @maxday
6768
* feat(configuration): export `SamplerConfigModel` type for use with `buildSamplerFromConfig` [#6536](https://github.com/open-telemetry/opentelemetry-js/pull/6536) @ravitheja4531-cell

experimental/packages/configuration/src/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,8 @@ export type {
1717
SpanExporter as SpanExporterConfigModel,
1818
SpanProcessor as SpanProcessorConfigModel,
1919
} from './models/tracerProviderModel';
20+
export type {
21+
NameStringValuePair as NameStringValuePairConfigModel,
22+
HttpTls as HttpTlsConfigModel,
23+
} from './models/commonModel';
2024
export { createConfigFactory } from './ConfigFactory';

experimental/packages/opentelemetry-sdk-node/src/start.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
diag,
1313
DiagConsoleLogger,
1414
metrics,
15+
trace,
1516
propagation,
1617
} from '@opentelemetry/api';
1718
import {
@@ -22,6 +23,8 @@ import {
2223
getPropagatorFromConfiguration,
2324
getResourceDetectorsFromConfiguration,
2425
getResourceFromConfiguration,
26+
getSpanLimitsFromConfiguration,
27+
getSpanProcessorsFromConfiguration,
2528
} from './utils';
2629
import { registerInstrumentations } from '@opentelemetry/instrumentation';
2730
import type { SDKComponents, SDKOptions } from './types';
@@ -40,6 +43,7 @@ import {
4043
} from '@opentelemetry/resources';
4144
import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks';
4245
import { ATTR_SERVICE_INSTANCE_ID } from './semconv';
46+
import { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';
4347

4448
/**
4549
* @experimental Function to start the OpenTelemetry Node SDK
@@ -71,6 +75,9 @@ export function startNodeSDK(sdkOptions: SDKOptions): {
7175
if (components.meterProvider) {
7276
metrics.setGlobalMeterProvider(components.meterProvider);
7377
}
78+
if (components.tracerProvider) {
79+
trace.setGlobalTracerProvider(components.tracerProvider);
80+
}
7481
if (components.propagator) {
7582
propagation.setGlobalPropagator(components.propagator);
7683
}
@@ -83,6 +90,9 @@ export function startNodeSDK(sdkOptions: SDKOptions): {
8390
if (components.meterProvider) {
8491
promises.push(components.meterProvider.shutdown());
8592
}
93+
if (components.tracerProvider) {
94+
promises.push(components.tracerProvider.shutdown());
95+
}
8696
await Promise.all(promises);
8797
};
8898
return { shutdown: shutdownFn };
@@ -134,6 +144,25 @@ function create(
134144
components.meterProvider = meterProvider;
135145
}
136146

147+
const spanProcessors = getSpanProcessorsFromConfiguration(config);
148+
if (spanProcessors) {
149+
const spanLimits = getSpanLimitsFromConfiguration(config);
150+
// TODO (6506): support sampler configuration from config
151+
const tracerProvider = new BasicTracerProvider({
152+
resource,
153+
spanProcessors,
154+
spanLimits,
155+
generalLimits: {
156+
attributeValueLengthLimit:
157+
config.attribute_limits?.attribute_value_length_limit,
158+
attributeCountLimit: config.attribute_limits?.attribute_count_limit,
159+
},
160+
// TODO (6616): support idGenerator configuration from config
161+
// TODO (6624): support for `meterProvider: components.meterProvider`
162+
});
163+
components.tracerProvider = tracerProvider;
164+
}
165+
137166
return components;
138167
}
139168

experimental/packages/opentelemetry-sdk-node/src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import type {
2020
SpanProcessor,
2121
IdGenerator,
2222
} from '@opentelemetry/sdk-trace-base';
23+
import type { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';
2324

2425
export interface NodeSDKConfiguration {
2526
autoDetectResources: boolean;
@@ -57,5 +58,6 @@ export interface SDKComponents {
5758
contextManager: ContextManager;
5859
loggerProvider?: LoggerProvider;
5960
meterProvider?: MeterProvider;
61+
tracerProvider?: BasicTracerProvider;
6062
propagator?: TextMapPropagator;
6163
}

experimental/packages/opentelemetry-sdk-node/src/utils.ts

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
import type {
3434
Sampler,
3535
SpanExporter,
36+
SpanLimits,
3637
SpanProcessor,
3738
} from '@opentelemetry/sdk-trace-base';
3839
import {
@@ -57,7 +58,10 @@ import type {
5758
InstrumentTypeConfigModel,
5859
AggregationConfigModel,
5960
PeriodicMetricReaderConfigModel,
61+
SpanExporterConfigModel,
6062
SamplerConfigModel,
63+
NameStringValuePairConfigModel,
64+
HttpTlsConfigModel,
6165
} from '@opentelemetry/configuration';
6266
import type {
6367
AggregationOption,
@@ -88,6 +92,7 @@ import {
8892
ConsoleLogRecordExporter,
8993
SimpleLogRecordProcessor,
9094
} from '@opentelemetry/sdk-logs';
95+
import * as fs from 'fs';
9196

9297
const RESOURCE_DETECTOR_ENVIRONMENT = 'env';
9398
const RESOURCE_DETECTOR_HOST = 'host';
@@ -675,6 +680,151 @@ export function getLogRecordProcessorsFromConfiguration(
675680
return undefined;
676681
}
677682

683+
export function getHeadersFromConfiguration(
684+
headers: NameStringValuePairConfigModel[] | undefined
685+
): Record<string, string> | undefined {
686+
if (!headers) {
687+
return undefined;
688+
}
689+
const result: Record<string, string> = {};
690+
headers.forEach(header => {
691+
result[header.name] = header.value;
692+
});
693+
return result;
694+
}
695+
696+
export function getHttpAgentOptionsFromTls(
697+
tls: HttpTlsConfigModel | undefined
698+
): { ca?: Buffer; cert?: Buffer; key?: Buffer } | undefined {
699+
if (tls && (tls.ca_file || tls.cert_file || tls.key_file)) {
700+
const httpsAgentOptions: { ca?: Buffer; cert?: Buffer; key?: Buffer } = {};
701+
if (tls.ca_file) {
702+
try {
703+
httpsAgentOptions.ca = fs.readFileSync(tls.ca_file);
704+
} catch (e) {
705+
diag.warn(`Failed to read TLS CA file at ${tls.ca_file}: ${e}`);
706+
}
707+
}
708+
if (tls.cert_file) {
709+
try {
710+
httpsAgentOptions.cert = fs.readFileSync(tls.cert_file);
711+
} catch (e) {
712+
diag.warn(`Failed to read TLS cert file at ${tls.cert_file}: ${e}`);
713+
}
714+
}
715+
if (tls.key_file) {
716+
try {
717+
httpsAgentOptions.key = fs.readFileSync(tls.key_file);
718+
} catch (e) {
719+
diag.warn(`Failed to read TLS key file at ${tls.key_file}: ${e}`);
720+
}
721+
}
722+
return httpsAgentOptions;
723+
}
724+
return undefined;
725+
}
726+
727+
export function getSpanExporter(
728+
exporter: SpanExporterConfigModel
729+
): SpanExporter | undefined {
730+
if (exporter.otlp_http) {
731+
const encoding = exporter.otlp_http.encoding;
732+
if (encoding === 'json') {
733+
return new OTLPHttpTraceExporter({
734+
compression:
735+
exporter.otlp_http.compression === 'gzip'
736+
? CompressionAlgorithm.GZIP
737+
: CompressionAlgorithm.NONE,
738+
url: exporter.otlp_http.endpoint,
739+
headers: getHeadersFromConfiguration(exporter.otlp_http.headers),
740+
timeoutMillis: exporter.otlp_http.timeout,
741+
httpAgentOptions: getHttpAgentOptionsFromTls(exporter.otlp_http.tls),
742+
});
743+
} else {
744+
return new OTLPProtoTraceExporter({
745+
compression:
746+
exporter.otlp_http.compression === 'gzip'
747+
? CompressionAlgorithm.GZIP
748+
: CompressionAlgorithm.NONE,
749+
url: exporter.otlp_http.endpoint,
750+
headers: getHeadersFromConfiguration(exporter.otlp_http.headers),
751+
timeoutMillis: exporter.otlp_http.timeout,
752+
httpAgentOptions: getHttpAgentOptionsFromTls(exporter.otlp_http.tls),
753+
});
754+
}
755+
} else if (exporter.otlp_grpc) {
756+
return new OTLPGrpcTraceExporter({
757+
compression:
758+
exporter.otlp_grpc.compression === 'gzip'
759+
? CompressionAlgorithm.GZIP
760+
: CompressionAlgorithm.NONE,
761+
url: exporter.otlp_grpc.endpoint,
762+
timeoutMillis: exporter.otlp_grpc.timeout,
763+
// TODO (6614): add support for credentials
764+
// TODO (6615): add metadata (headers) support
765+
});
766+
} else if (exporter.console) {
767+
return new ConsoleSpanExporter();
768+
}
769+
diag.warn(`Unsupported Exporter value. No Span Exporter registered`);
770+
return undefined;
771+
}
772+
773+
export function getSpanProcessorsFromConfiguration(
774+
config: ConfigurationModel
775+
): SpanProcessor[] | undefined {
776+
const spanProcessors: SpanProcessor[] = [];
777+
config.tracer_provider?.processors?.forEach(processor => {
778+
if (processor.batch) {
779+
const exporter = getSpanExporter(processor.batch.exporter);
780+
if (exporter) {
781+
spanProcessors.push(
782+
new BatchSpanProcessor(exporter, {
783+
maxQueueSize: processor.batch.max_queue_size,
784+
maxExportBatchSize: processor.batch.max_export_batch_size,
785+
scheduledDelayMillis: processor.batch.schedule_delay,
786+
exportTimeoutMillis: processor.batch.export_timeout,
787+
})
788+
);
789+
}
790+
}
791+
if (processor.simple) {
792+
const exporter = getSpanExporter(processor.simple.exporter);
793+
if (exporter) {
794+
spanProcessors.push(new SimpleSpanProcessor(exporter));
795+
}
796+
}
797+
});
798+
if (spanProcessors.length > 0) {
799+
return spanProcessors;
800+
}
801+
return undefined;
802+
}
803+
804+
export function getSpanLimitsFromConfiguration(
805+
config: ConfigurationModel
806+
): SpanLimits | undefined {
807+
if (config.tracer_provider?.limits) {
808+
const limitsConfig = config.tracer_provider.limits;
809+
const spanLimits: SpanLimits = {};
810+
spanLimits.attributeCountLimit = limitsConfig.attribute_count_limit ?? 128;
811+
spanLimits.eventCountLimit = limitsConfig.event_count_limit ?? 128;
812+
spanLimits.linkCountLimit = limitsConfig.link_count_limit ?? 128;
813+
spanLimits.attributePerLinkCountLimit =
814+
limitsConfig.link_attribute_count_limit ?? 128;
815+
spanLimits.attributePerEventCountLimit =
816+
limitsConfig.event_attribute_count_limit ?? 128;
817+
818+
if (limitsConfig.attribute_value_length_limit != null) {
819+
spanLimits.attributeValueLengthLimit =
820+
limitsConfig.attribute_value_length_limit;
821+
}
822+
823+
return spanLimits;
824+
}
825+
return undefined;
826+
}
827+
678828
export function getMeterReadersFromConfiguration(
679829
config: ConfigurationModel
680830
): IMetricReader[] | undefined {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIIEpQIBAAKCAQEA3Tz2mr7SZiAMfQyuvBjM9Oi..Z1BjP5CE/Wm/Rr500P
3+
RK+Lh9x5eJPo5CAZ3/ANBE0sTK0ZsDGMak2m1g7..3VHqIxFTz0Ta1d+NAj
4+
wnLe4nOb7/eEJbDPkk05ShhBrJGBKKxb8n104o/..PdzbFMIyNjJzBM2o5y
5+
5A13wiLitEO7nco2WfyYkQzaxCw0AwzlkVHiIyC..71pSzkv6sv+4IDMbT/
6+
XpCo8L6wTarzrywnQsh+etLD6FtTjYbbrvZ8RQM..Hg2qxraAV++HNBYmNW
7+
s0duEdjUbJK+ZarypXI9TtnS4o1Ckj7POfljiQI..IBAFyidxtqRQyv5KrD
8+
kbJ+q+rsJxQlaipn2M4lGuQJEfIxELFDyd3XpxP..Un/82NZNXlPmRIopXs
9+
2T91jiLZEUKQw+n73j26adTbteuEaPGSrTZxBLR..yssO0wWomUyILqVeti
10+
6AkL0NJAuKcucHGqWVgUIa4g1haE0ilcm6dWUDo..fd+PpzdCJf1s4NdUWK
11+
YV2GJcutGQb+jqT5DTUqAgST7N8M28rwjK6nVMI..BUpP0xpPnuYDyPOw6x
12+
4hBt8DZQYyduzIXBXRBKNiNdv8fum68/5klHxp6..4HRkMUL958UVeljUsT
13+
BFQlO9UCgYEA/VqzXVzlz8K36VSTMPEhB5zBATV..PRiXtYK1YpYV4/jSUj
14+
vvT4hP8uoYNC+BlEMi98LtnxZIh0V4rqHDsScAq..VyeSLH0loKMZgpwFEm
15+
bEIDnEOD0nKrfT/9K9sPYgvB43wsLEtUujaYw3W..Liy0WKmB8CgYEA34xn
16+
1QlOOhHBn9Z8qYjoDYhvcj+a89tD9eMPhesfQFw..rsfGcXIonFmWdVygbe
17+
6Doihc+GIYIq/QP4jgMksE1ADvczJSke92ZfE2i..fitBpQERNJO0BlabfP
18+
ALs5NssKNmLkWS2U2BHCbv4DzDXwiQB37KPOL1c..kBHfF2/htIs20d1UVL
19+
+PK+aXKwguI6bxLGZ3of0UH+mGsSl0mkp7kYZCm..OTQtfeRqP8rDSC7DgA
20+
kHc5ajYqh04AzNFaxjRo+M3IGICUaOdKnXd0Fda..QwfoaX4QlRTgLqb7AN
21+
ZTzM9WbmnYoXrx17kZlT3lsCgYEAm757XI3WJVj..WoLj1+v48WyoxZpcai
22+
uv9bT4Cj+lXRS+gdKHK+SH7J3x2CRHVS+WH/SVC..DxuybvebDoT0TkKiCj
23+
BWQaGzCaJqZa+POHK0klvS+9ln0/6k539p95tfX..X4TCzbVG6+gJiX0ysz
24+
Yfehn5MCgYEAkMiKuWHCsVyCab3RUf6XA9gd3qY..fCTIGtS1tR5PgFIV+G
25+
engiVoWc/hkj8SBHZz1n1xLN7KDf8ySU06MDggB..hJ+gXJKy+gf3mF5Kmj
26+
DtkpjGHQzPF6vOe907y5NQLvVFGXUq/FIJZxB8k..fJdHEm2M4=
27+
-----END RSA PRIVATE KEY-----
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIEczCCA1ugAwIBAgIBADANBgkqhkiG9w0BAQQFAD..AkGA1UEBhMCR0Ix
3+
EzARBgNVBAgTClNvbWUtU3RhdGUxFDASBgNVBAoTC0..0EgTHRkMTcwNQYD
4+
VQQLEy5DbGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcn..XRpb24gQXV0aG9y
5+
aXR5MRQwEgYDVQQDEwtCZXN0IENBIEx0ZDAeFw0wMD..TUwMTZaFw0wMTAy
6+
MDQxOTUwMTZaMIGHMQswCQYDVQQGEwJHQjETMBEGA1..29tZS1TdGF0ZTEU
7+
MBIGA1UEChMLQmVzdCBDQSBMdGQxNzA1BgNVBAsTLk..DEgUHVibGljIFBy
8+
aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFD..AMTC0Jlc3QgQ0Eg
9+
THRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCg..Tz2mr7SZiAMfQyu
10+
vBjM9OiJjRazXBZ1BjP5CE/Wm/Rr500PRK+Lh9x5eJ../ANBE0sTK0ZsDGM
11+
ak2m1g7oruI3dY3VHqIxFTz0Ta1d+NAjwnLe4nOb7/..k05ShhBrJGBKKxb
12+
8n104o/5p8HAsZPdzbFMIyNjJzBM2o5y5A13wiLitE..fyYkQzaxCw0Awzl
13+
kVHiIyCuaF4wj571pSzkv6sv+4IDMbT/XpCo8L6wTa..sh+etLD6FtTjYbb
14+
rvZ8RQM1tlKdoMHg2qxraAV++HNBYmNWs0duEdjUbJ..XI9TtnS4o1Ckj7P
15+
OfljiQIDAQABo4HnMIHkMB0GA1UdDgQWBBQ8urMCRL..5AkIp9NJHJw5TCB
16+
tAYDVR0jBIGsMIGpgBQ8urMCRLYYMHUKU5AkIp9NJH..aSBijCBhzELMAkG
17+
A1UEBhMCR0IxEzARBgNVBAgTClNvbWUtU3RhdGUxFD..AoTC0Jlc3QgQ0Eg
18+
THRkMTcwNQYDVQQLEy5DbGFzcyAxIFB1YmxpYyBQcm..ENlcnRpZmljYXRp
19+
b24gQXV0aG9yaXR5MRQwEgYDVQQDEwtCZXN0IENBIE..DAMBgNVHRMEBTAD
20+
AQH/MA0GCSqGSIb3DQEBBAUAA4IBAQC1uYBcsSncwA..DCsQer772C2ucpX
21+
xQUE/C0pWWm6gDkwd5D0DSMDJRqV/weoZ4wC6B73f5..bLhGYHaXJeSD6Kr
22+
XcoOwLdSaGmJYslLKZB3ZIDEp0wYTGhgteb6JFiTtn..sf2xdrYfPCiIB7g
23+
BMAV7Gzdc4VspS6ljrAhbiiawdBiQlQmsBeFz9JkF4..b3l8BoGN+qMa56Y
24+
It8una2gY4l2O//on88r5IWJlm1L0oA8e4fR2yrBHX..adsGeFKkyNrwGi/
25+
7vQMfXdGsRrXNGRGnX+vWDZ3/zWI0joDtCkNnqEpVn..HoX
26+
-----END CERTIFICATE-----
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIEczCCA1ugAwIBAgIBADANBgkqhkiG9w0BAQQFAD..AkGA1UEBhMCR0Ix
3+
EzARBgNVBAgTClNvbWUtU3RhdGUxFDASBgNVBAoTC0..0EgTHRkMTcwNQYD
4+
VQQLEy5DbGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcn..XRpb24gQXV0aG9y
5+
aXR5MRQwEgYDVQQDEwtCZXN0IENBIEx0ZDAeFw0wMD..TUwMTZaFw0wMTAy
6+
MDQxOTUwMTZaMIGHMQswCQYDVQQGEwJHQjETMBEGA1..29tZS1TdGF0ZTEU
7+
MBIGA1UEChMLQmVzdCBDQSBMdGQxNzA1BgNVBAsTLk..DEgUHVibGljIFBy
8+
aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFD..AMTC0Jlc3QgQ0Eg
9+
THRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCg..Tz2mr7SZiAMfQyu
10+
vBjM9OiJjRazXBZ1BjP5CE/Wm/Rr500PRK+Lh9x5eJ../ANBE0sTK0ZsDGM
11+
ak2m1g7oruI3dY3VHqIxFTz0Ta1d+NAjwnLe4nOb7/..k05ShhBrJGBKKxb
12+
8n104o/5p8HAsZPdzbFMIyNjJzBM2o5y5A13wiLitE..fyYkQzaxCw0Awzl
13+
kVHiIyCuaF4wj571pSzkv6sv+4IDMbT/XpCo8L6wTa..sh+etLD6FtTjYbb
14+
rvZ8RQM1tlKdoMHg2qxraAV++HNBYmNWs0duEdjUbJ..XI9TtnS4o1Ckj7P
15+
OfljiQIDAQABo4HnMIHkMB0GA1UdDgQWBBQ8urMCRL..5AkIp9NJHJw5TCB
16+
tAYDVR0jBIGsMIGpgBQ8urMCRLYYMHUKU5AkIp9NJH..aSBijCBhzELMAkG
17+
A1UEBhMCR0IxEzARBgNVBAgTClNvbWUtU3RhdGUxFD..AoTC0Jlc3QgQ0Eg
18+
THRkMTcwNQYDVQQLEy5DbGFzcyAxIFB1YmxpYyBQcm..ENlcnRpZmljYXRp
19+
b24gQXV0aG9yaXR5MRQwEgYDVQQDEwtCZXN0IENBIE..DAMBgNVHRMEBTAD
20+
AQH/MA0GCSqGSIb3DQEBBAUAA4IBAQC1uYBcsSncwA..DCsQer772C2ucpX
21+
xQUE/C0pWWm6gDkwd5D0DSMDJRqV/weoZ4wC6B73f5..bLhGYHaXJeSD6Kr
22+
XcoOwLdSaGmJYslLKZB3ZIDEp0wYTGhgteb6JFiTtn..sf2xdrYfPCiIB7g
23+
BMAV7Gzdc4VspS6ljrAhbiiawdBiQlQmsBeFz9JkF4..b3l8BoGN+qMa56Y
24+
It8una2gY4l2O//on88r5IWJlm1L0oA8e4fR2yrBHX..adsGeFKkyNrwGi/
25+
7vQMfXdGsRrXNGRGnX+vWDZ3/zWI0joDtCkNnqEpVn..HoX
26+
-----END CERTIFICATE-----

0 commit comments

Comments
 (0)