From 4fed8c3fd5532d6778d3276e55e32e5ed4343d8c Mon Sep 17 00:00:00 2001 From: Karsten Schnitter Date: Mon, 11 Dec 2023 17:13:40 +0100 Subject: [PATCH 1/6] Add OpenTelemetry Signal Exporters for Cloud Logging Register signal exporters for logs, metrics and traces, that forward signals to SAP Cloud Logging, if an appropriate service binding is found or do a non operation otherwise. This allows developers to explicitly configure the export, e.g. by `otel.logs.exporter=cloud-logging`. Additional exporters can be added with comma-separated labels. Signed-off-by: Karsten Schnitter --- .../dependency-reduced-pom.xml | 12 +- .../pom.xml | 9 +- ...oggingConfigurationCustomizerProvider.java | 2 + .../ext/exporter/CloudLoggingCredentials.java | 87 ++++++++++++ .../CloudLoggingLogsExporterProvider.java | 80 +++++++++++ .../CloudLoggingMetricsExporterProvider.java | 129 ++++++++++++++++++ .../CloudLoggingServicesProvider.java | 49 +++++++ .../CloudLoggingSpanExporterProvider.java | 83 +++++++++++ .../ext/exporter/MultiMetricExporter.java | 97 +++++++++++++ .../ext/exporter/NoopLogRecordExporter.java | 30 ++++ .../ext/exporter/NoopMetricExporter.java | 46 +++++++ .../agent/ext/exporter/NoopSpanExporter.java | 32 +++++ ...logs.ConfigurableLogRecordExporterProvider | 1 + ...metrics.ConfigurableMetricExporterProvider | 1 + ...pi.traces.ConfigurableSpanExporterProvider | 1 + 15 files changed, 657 insertions(+), 2 deletions(-) create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingCredentials.java create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingLogsExporterProvider.java create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingMetricsExporterProvider.java create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingServicesProvider.java create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingSpanExporterProvider.java create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/MultiMetricExporter.java create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopLogRecordExporter.java create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopMetricExporter.java create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopSpanExporter.java create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.logs.ConfigurableLogRecordExporterProvider create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider diff --git a/cf-java-logging-support-opentelemetry-agent-extension/dependency-reduced-pom.xml b/cf-java-logging-support-opentelemetry-agent-extension/dependency-reduced-pom.xml index 4af6f8d..4abce9a 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/dependency-reduced-pom.xml +++ b/cf-java-logging-support-opentelemetry-agent-extension/dependency-reduced-pom.xml @@ -32,6 +32,10 @@ io.opentelemetry com.fasterxml.jackson.core + com.squareup.okhttp3 + com.squareup.okio + org.jetbrains.kotlin + org.jetbrains @@ -58,7 +62,13 @@ io.opentelemetry opentelemetry-sdk-extension-autoconfigure 1.31.0 - provided + compile + + + io.opentelemetry + opentelemetry-exporter-otlp + 1.31.0 + compile org.slf4j diff --git a/cf-java-logging-support-opentelemetry-agent-extension/pom.xml b/cf-java-logging-support-opentelemetry-agent-extension/pom.xml index a4be8a8..6abaff7 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/pom.xml +++ b/cf-java-logging-support-opentelemetry-agent-extension/pom.xml @@ -49,7 +49,10 @@ io.opentelemetry opentelemetry-sdk-extension-autoconfigure - provided + + + io.opentelemetry + opentelemetry-exporter-otlp io.pivotal.cfenv @@ -83,6 +86,10 @@ io.opentelemetry com.fasterxml.jackson.core + com.squareup.okhttp3 + com.squareup.okio + org.jetbrains.kotlin + org.jetbrains diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/CloudLoggingConfigurationCustomizerProvider.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/CloudLoggingConfigurationCustomizerProvider.java index 9cad03a..b02d657 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/CloudLoggingConfigurationCustomizerProvider.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/CloudLoggingConfigurationCustomizerProvider.java @@ -13,6 +13,8 @@ public class CloudLoggingConfigurationCustomizerProvider implements AutoConfigur public void customize(AutoConfigurationCustomizer autoConfiguration) { autoConfiguration .addPropertiesSupplier(new CloudLoggingBindingPropertiesSupplier(cfEnv)); + + // ConfigurableLogRecordExporterProvider } } diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingCredentials.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingCredentials.java new file mode 100644 index 0000000..a023d3d --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingCredentials.java @@ -0,0 +1,87 @@ +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; + +import io.pivotal.cfenv.core.CfCredentials; + +import java.nio.charset.StandardCharsets; +import java.util.logging.Logger; + +class CloudLoggingCredentials { + + private static final Logger LOG = Logger.getLogger(CloudLoggingCredentials.class.getName()); + + private static final String CRED_OTLP_ENDPOINT = "ingest-otlp-endpoint"; + private static final String CRED_OTLP_CLIENT_KEY = "ingest-otlp-key"; + private static final String CRED_OTLP_CLIENT_CERT = "ingest-otlp-cert"; + private static final String CRED_OTLP_SERVER_CERT = "server-ca"; + private static final String CLOUD_LOGGING_ENDPOINT_PREFIX = "https://"; + + + private String endpoint; + private byte[] clientKey; + private byte[] clientCert; + private byte[] serverCert; + + private CloudLoggingCredentials() { + } + + static CloudLoggingCredentials parseCredentials(CfCredentials cfCredentials) { + CloudLoggingCredentials parsed = new CloudLoggingCredentials(); + parsed.endpoint = CLOUD_LOGGING_ENDPOINT_PREFIX + cfCredentials.getString(CRED_OTLP_ENDPOINT); + parsed.clientKey = getPEMBytes(cfCredentials, CRED_OTLP_CLIENT_KEY); + parsed.clientCert = getPEMBytes(cfCredentials, CRED_OTLP_CLIENT_CERT); + parsed.serverCert = getPEMBytes(cfCredentials, CRED_OTLP_SERVER_CERT); + return parsed; + } + + private static byte[] getPEMBytes(CfCredentials credentials, String key) { + String raw = credentials.getString(key); + return raw == null ? null : raw.trim().replace("\\n", "\n").getBytes(StandardCharsets.UTF_8); + } + + private static boolean isBlank(String text) { + return text == null || text.trim().isEmpty(); + } + + private static boolean isNullOrEmpty(byte[] bytes) { + return bytes == null || bytes.length == 0; + } + + public boolean validate() { + if (isBlank(endpoint)) { + LOG.warning("Credential \"" + CRED_OTLP_ENDPOINT + "\" not found. Skipping cloud-logging exporter configuration"); + return false; + } + + if (isNullOrEmpty(clientKey)) { + LOG.warning("Credential \"" + CRED_OTLP_CLIENT_KEY + "\" not found. Skipping cloud-logging exporter configuration"); + return false; + } + + if (isNullOrEmpty(clientCert)) { + LOG.warning("Credential \"" + CRED_OTLP_CLIENT_CERT + "\" not found. Skipping cloud-logging exporter configuration"); + return false; + } + + if (isNullOrEmpty(serverCert)) { + LOG.warning("Credential \"" + CRED_OTLP_SERVER_CERT + "\" not found. Skipping cloud-logging exporter configuration"); + return false; + } + return true; + } + + public String getEndpoint() { + return endpoint; + } + + public byte[] getClientKey() { + return clientKey; + } + + public byte[] getClientCert() { + return clientCert; + } + + public byte[] getServerCert() { + return serverCert; + } +} diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingLogsExporterProvider.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingLogsExporterProvider.java new file mode 100644 index 0000000..33159b2 --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingLogsExporterProvider.java @@ -0,0 +1,80 @@ +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; + +import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; +import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.logs.ConfigurableLogRecordExporterProvider; +import io.opentelemetry.sdk.common.export.RetryPolicy; +import io.opentelemetry.sdk.logs.export.LogRecordExporter; +import io.pivotal.cfenv.core.CfEnv; +import io.pivotal.cfenv.core.CfService; + +import java.time.Duration; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class CloudLoggingLogsExporterProvider implements ConfigurableLogRecordExporterProvider { + + private static final Logger LOG = Logger.getLogger(CloudLoggingLogsExporterProvider.class.getName()); + + private final Function> servicesProvider; + + public CloudLoggingLogsExporterProvider() { + this(config -> new CloudLoggingServicesProvider(config, new CfEnv()).get()); + } + + public CloudLoggingLogsExporterProvider(Function> serviceProvider) { + this.servicesProvider = serviceProvider; + } + + private static String getCompression(ConfigProperties config) { + String compression = config.getString("otel.exporter.cloud-logging.logs.compression"); + return compression != null ? compression : config.getString("otel.exporter.cloud-logging.compression", "gzip"); + } + + private static Duration getTimeOut(ConfigProperties config) { + Duration timeout = config.getDuration("otel.exporter.cloud-logging.logs.timeout"); + return timeout != null ? timeout : config.getDuration("otel.exporter.cloud-logging.timeout"); + } + + @Override + public String getName() { + return "cloud-logging"; + } + + @Override + public LogRecordExporter createExporter(ConfigProperties config) { + List exporters = servicesProvider.apply(config) + .map(svc -> createExporter(config, svc)) + .filter(exp -> !(exp instanceof NoopLogRecordExporter)) + .collect(Collectors.toList()); + return LogRecordExporter.composite(exporters); + } + + private LogRecordExporter createExporter(ConfigProperties config, CfService service) { + LOG.info("Creating logs exporter for service binding " + service.getName() + " (" + service.getLabel() + ")"); + CloudLoggingCredentials credentials = CloudLoggingCredentials.parseCredentials(service.getCredentials()); + if (!credentials.validate()) { + return NoopLogRecordExporter.getInstance(); + } + + OtlpGrpcLogRecordExporterBuilder builder = OtlpGrpcLogRecordExporter.builder(); + builder.setEndpoint(credentials.getEndpoint()) + .setCompression(getCompression(config)) + .setClientTls(credentials.getClientKey(), credentials.getClientCert()) + .setTrustedCertificates(credentials.getServerCert()) + .setRetryPolicy(RetryPolicy.getDefault()); + + Duration timeOut = getTimeOut(config); + if (timeOut != null) { + builder.setTimeout(timeOut); + } + + LOG.info("Created logs exporter for service binding " + service.getName() + " (" + service.getLabel() + ")"); + return builder.build(); + } +} diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingMetricsExporterProvider.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingMetricsExporterProvider.java new file mode 100644 index 0000000..4f4da25 --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingMetricsExporterProvider.java @@ -0,0 +1,129 @@ +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; + +import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter; +import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; +import io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider; +import io.opentelemetry.sdk.common.export.RetryPolicy; +import io.opentelemetry.sdk.metrics.Aggregation; +import io.opentelemetry.sdk.metrics.InstrumentType; +import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; +import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector; +import io.opentelemetry.sdk.metrics.export.MetricExporter; +import io.opentelemetry.sdk.metrics.internal.aggregator.AggregationUtil; +import io.pivotal.cfenv.core.CfEnv; +import io.pivotal.cfenv.core.CfService; + +import java.time.Duration; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.function.Function; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static io.opentelemetry.sdk.metrics.Aggregation.explicitBucketHistogram; + +public class CloudLoggingMetricsExporterProvider implements ConfigurableMetricExporterProvider { + + private static final Logger LOG = Logger.getLogger(CloudLoggingMetricsExporterProvider.class.getName()); + + private final Function> servicesProvider; + + public CloudLoggingMetricsExporterProvider() { + this(config -> new CloudLoggingServicesProvider(config, new CfEnv()).get()); + } + + public CloudLoggingMetricsExporterProvider(Function> serviceProvider) { + this.servicesProvider = serviceProvider; + } + + private static String getCompression(ConfigProperties config) { + String compression = config.getString("otel.exporter.cloud-logging.metrics.compression"); + return compression != null ? compression : config.getString("otel.exporter.cloud-logging.compression", "gzip"); + } + + private static Duration getTimeOut(ConfigProperties config) { + Duration timeout = config.getDuration("otel.exporter.cloud-logging.metrics.timeout"); + return timeout != null ? timeout : config.getDuration("otel.exporter.cloud-logging.timeout"); + } + + private static AggregationTemporalitySelector getAggregationTemporalitySelector(ConfigProperties config) { + String temporalityStr = config.getString("otel.exporter.cloud-logging.metrics.temporality.preference"); + if (temporalityStr == null) { + return AggregationTemporalitySelector.alwaysCumulative(); + } + AggregationTemporalitySelector temporalitySelector; + switch (temporalityStr.toLowerCase(Locale.ROOT)) { + case "cumulative": + return AggregationTemporalitySelector.alwaysCumulative(); + case "delta": + return AggregationTemporalitySelector.deltaPreferred(); + case "lowmemory": + return AggregationTemporalitySelector.lowMemory(); + default: + throw new ConfigurationException("Unrecognized aggregation temporality: " + temporalityStr); + } + } + + private static DefaultAggregationSelector getDefaultAggregationSelector(ConfigProperties config) { + String defaultHistogramAggregation = + config.getString("otel.exporter.cloud-logging.metrics.default.histogram.aggregation"); + if (defaultHistogramAggregation == null) { + return DefaultAggregationSelector.getDefault().with(InstrumentType.HISTOGRAM, Aggregation.defaultAggregation()); + } + if (AggregationUtil.aggregationName(Aggregation.base2ExponentialBucketHistogram()) + .equalsIgnoreCase(defaultHistogramAggregation)) { + return + DefaultAggregationSelector.getDefault() + .with(InstrumentType.HISTOGRAM, Aggregation.base2ExponentialBucketHistogram()); + } else if (AggregationUtil.aggregationName(explicitBucketHistogram()) + .equalsIgnoreCase(defaultHistogramAggregation)) { + return DefaultAggregationSelector.getDefault().with(InstrumentType.HISTOGRAM, Aggregation.explicitBucketHistogram()); + } else { + throw new ConfigurationException( + "Unrecognized default histogram aggregation: " + defaultHistogramAggregation); + } + } + + @Override + public String getName() { + return "cloud-logging"; + } + + @Override + public MetricExporter createExporter(ConfigProperties config) { + List exporters = servicesProvider.apply(config) + .map(svc -> createExporter(config, svc)) + .filter(exp -> !(exp instanceof NoopMetricExporter)) + .collect(Collectors.toList()); + return new MultiMetricExporter(getAggregationTemporalitySelector(config), getDefaultAggregationSelector(config), exporters); + } + + private MetricExporter createExporter(ConfigProperties config, CfService service) { + LOG.info("Creating metrics exporter for service binding " + service.getName() + " (" + service.getLabel() + ")"); + CloudLoggingCredentials credentials = CloudLoggingCredentials.parseCredentials(service.getCredentials()); + if (!credentials.validate()) { + return NoopMetricExporter.getInstance(); + } + + OtlpGrpcMetricExporterBuilder builder = OtlpGrpcMetricExporter.builder(); + builder.setEndpoint(credentials.getEndpoint()) + .setCompression(getCompression(config)) + .setClientTls(credentials.getClientKey(), credentials.getClientCert()) + .setTrustedCertificates(credentials.getServerCert()) + .setRetryPolicy(RetryPolicy.getDefault()) + .setAggregationTemporalitySelector(getAggregationTemporalitySelector(config)) + .setDefaultAggregationSelector(getDefaultAggregationSelector(config)); + + Duration timeOut = getTimeOut(config); + if (timeOut != null) { + builder.setTimeout(timeOut); + } + + LOG.info("Created metrics exporter for service binding " + service.getName() + " (" + service.getLabel() + ")"); + return builder.build(); + } +} diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingServicesProvider.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingServicesProvider.java new file mode 100644 index 0000000..1e35c2b --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingServicesProvider.java @@ -0,0 +1,49 @@ +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; + +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.pivotal.cfenv.core.CfEnv; +import io.pivotal.cfenv.core.CfService; + +import java.util.List; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class CloudLoggingServicesProvider implements Supplier> { + + private static final String DEFAULT_USER_PROVIDED_LABEL = "user-provided"; + private static final String DEFAULT_CLOUD_LOGGING_LABEL = "cloud-logging"; + private static final String DEFAULT_CLOUD_LOGGING_TAG = "Cloud Logging"; + + private final List services; + + public CloudLoggingServicesProvider(ConfigProperties config, CfEnv cfEnv) { + String userProvidedLabel = getUserProvidedLabel(config); + String cloudLoggingLabel = getCloudLoggingLabel(config); + String cloudLoggingTag = getCloudLoggingTag(config); + List userProvided = cfEnv.findServicesByLabel(userProvidedLabel); + List managed = cfEnv.findServicesByLabel(cloudLoggingLabel); + this.services = Stream.concat(userProvided.stream(), managed.stream()) + .filter(svc -> svc.existsByTagIgnoreCase(cloudLoggingTag)) + .collect(Collectors.toList()); + } + + private String getUserProvidedLabel(ConfigProperties config) { + return config.getString("otel.javaagent.extension.sap.cf.binding.user-provided.label", DEFAULT_USER_PROVIDED_LABEL); + } + + private String getCloudLoggingLabel(ConfigProperties config) { + String fromOwnProperties = System.getProperty("com.sap.otel.extension.cloud-logging.label", DEFAULT_CLOUD_LOGGING_LABEL); + return config.getString("otel.javaagent.extension.sap.cf.binding.cloud-logging.label", fromOwnProperties); + } + + private String getCloudLoggingTag(ConfigProperties config) { + String fromOwnProperties = System.getProperty("com.sap.otel.extension.cloud-logging.tag", DEFAULT_CLOUD_LOGGING_TAG); + return config.getString("otel.javaagent.extension.sap.cf.binding.cloud-logging.tag", fromOwnProperties); + } + + @Override + public Stream get() { + return services.stream(); + } +} diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingSpanExporterProvider.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingSpanExporterProvider.java new file mode 100644 index 0000000..a58af2d --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingSpanExporterProvider.java @@ -0,0 +1,83 @@ +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; + +import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; +import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder; +import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; +import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider; +import io.opentelemetry.sdk.common.export.RetryPolicy; +import io.opentelemetry.sdk.logs.export.LogRecordExporter; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import io.pivotal.cfenv.core.CfEnv; +import io.pivotal.cfenv.core.CfService; + +import java.time.Duration; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class CloudLoggingSpanExporterProvider implements ConfigurableSpanExporterProvider { + + private static final Logger LOG = Logger.getLogger(CloudLoggingSpanExporterProvider.class.getName()); + + private final Function> servicesProvider; + + public CloudLoggingSpanExporterProvider() { + this(config -> new CloudLoggingServicesProvider(config, new CfEnv()).get()); + } + + public CloudLoggingSpanExporterProvider(Function> serviceProvider) { + this.servicesProvider = serviceProvider; + } + + private static String getCompression(ConfigProperties config) { + String compression = config.getString("otel.exporter.cloud-logging.traces.compression"); + return compression != null ? compression : config.getString("otel.exporter.cloud-logging.compression", "gzip"); + } + + private static Duration getTimeOut(ConfigProperties config) { + Duration timeout = config.getDuration("otel.exporter.cloud-logging.traces.timeout"); + return timeout != null ? timeout : config.getDuration("otel.exporter.cloud-logging.timeout"); + } + + @Override + public String getName() { + return "cloud-logging"; + } + + @Override + public SpanExporter createExporter(ConfigProperties config) { + List exporters = servicesProvider.apply(config) + .map(svc -> createExporter(config, svc)) + .filter(exp -> !(exp instanceof NoopSpanExporter)) + .collect(Collectors.toList()); + return SpanExporter.composite(exporters); + } + + private SpanExporter createExporter(ConfigProperties config, CfService service) { + LOG.info("Creating span exporter for service binding " + service.getName() + " (" + service.getLabel() + ")"); + CloudLoggingCredentials credentials = CloudLoggingCredentials.parseCredentials(service.getCredentials()); + if (!credentials.validate()) { + return NoopSpanExporter.getInstance(); + } + + OtlpGrpcSpanExporterBuilder builder = OtlpGrpcSpanExporter.builder(); + builder.setEndpoint(credentials.getEndpoint()) + .setCompression(getCompression(config)) + .setClientTls(credentials.getClientKey(), credentials.getClientCert()) + .setTrustedCertificates(credentials.getServerCert()) + .setRetryPolicy(RetryPolicy.getDefault()); + + Duration timeOut = getTimeOut(config); + if (timeOut != null) { + builder.setTimeout(timeOut); + } + + LOG.info("Created span exporter for service binding " + service.getName() + " (" + service.getLabel() + ")"); + return builder.build(); + } +} diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/MultiMetricExporter.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/MultiMetricExporter.java new file mode 100644 index 0000000..9074f28 --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/MultiMetricExporter.java @@ -0,0 +1,97 @@ +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; + +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.metrics.Aggregation; +import io.opentelemetry.sdk.metrics.InstrumentType; +import io.opentelemetry.sdk.metrics.data.AggregationTemporality; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; +import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector; +import io.opentelemetry.sdk.metrics.export.MetricExporter; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +class MultiMetricExporter implements MetricExporter { + + private static final Logger LOG = Logger.getLogger(MultiMetricExporter.class.getName()); + + private final AggregationTemporalitySelector aggregationTemporalitySelector; + private final DefaultAggregationSelector defaultAggregationSelector; + private final List metricExporters; + + MultiMetricExporter(AggregationTemporalitySelector aggregationTemporalitySelector, + DefaultAggregationSelector defaultAggregationSelector, + List metricExporters) { + this.aggregationTemporalitySelector = aggregationTemporalitySelector; + this.defaultAggregationSelector = defaultAggregationSelector; + this.metricExporters = metricExporters; + } + + public CompletableResultCode export(Collection metrics) { + List results = new ArrayList<>(metricExporters.size()); + for (MetricExporter metricExporter : metricExporters) { + CompletableResultCode exportResult; + try { + exportResult = metricExporter.export(metrics); + results.add(exportResult); + } catch (RuntimeException e) { + LOG.log(Level.WARNING, "Exception thrown by the export.", e); + results.add(CompletableResultCode.ofFailure()); + } + } + return CompletableResultCode.ofAll(results); + } + + public CompletableResultCode flush() { + List results = new ArrayList<>(this.metricExporters.size()); + for (MetricExporter metricExporter : metricExporters) { + CompletableResultCode flushResult; + try { + flushResult = metricExporter.flush(); + results.add(flushResult); + } catch (RuntimeException e) { + LOG.log(Level.WARNING, "Exception thrown by the flush.", e); + results.add(CompletableResultCode.ofFailure()); + } + } + return CompletableResultCode.ofAll(results); + } + + public CompletableResultCode shutdown() { + List results = new ArrayList<>(this.metricExporters.size()); + for (MetricExporter metricExporter : metricExporters) { + CompletableResultCode shutdownResult; + try { + shutdownResult = metricExporter.shutdown(); + results.add(shutdownResult); + } catch (RuntimeException e) { + LOG.log(Level.WARNING, "Exception thrown by the shutdown.", e); + results.add(CompletableResultCode.ofFailure()); + } + } + return CompletableResultCode.ofAll(results); + } + + public String toString() { + return "MultiMetricExporter" + + metricExporters.stream() + .map(Object::toString) + .collect(Collectors.joining(",", "{metricsExporters=", "}")); + } + + @Override + public AggregationTemporality getAggregationTemporality(InstrumentType instrumentType) { + return aggregationTemporalitySelector.getAggregationTemporality(instrumentType); + } + + @Override + public Aggregation getDefaultAggregation(InstrumentType instrumentType) { + return defaultAggregationSelector.getDefaultAggregation(instrumentType); + } + +} \ No newline at end of file diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopLogRecordExporter.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopLogRecordExporter.java new file mode 100644 index 0000000..e83dc96 --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopLogRecordExporter.java @@ -0,0 +1,30 @@ +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; + +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.logs.data.LogRecordData; +import io.opentelemetry.sdk.logs.export.LogRecordExporter; + +import java.util.Collection; + +class NoopLogRecordExporter implements LogRecordExporter { + private static final LogRecordExporter INSTANCE = new NoopLogRecordExporter(); + + NoopLogRecordExporter() { + } + + static LogRecordExporter getInstance() { + return INSTANCE; + } + + public CompletableResultCode export(Collection logs) { + return CompletableResultCode.ofSuccess(); + } + + public CompletableResultCode flush() { + return CompletableResultCode.ofSuccess(); + } + + public CompletableResultCode shutdown() { + return CompletableResultCode.ofSuccess(); + } +} diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopMetricExporter.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopMetricExporter.java new file mode 100644 index 0000000..862fed5 --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopMetricExporter.java @@ -0,0 +1,46 @@ +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; + +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.logs.export.LogRecordExporter; +import io.opentelemetry.sdk.metrics.InstrumentType; +import io.opentelemetry.sdk.metrics.data.AggregationTemporality; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; +import io.opentelemetry.sdk.metrics.export.MetricExporter; + +import java.util.Collection; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class NoopMetricExporter implements MetricExporter { + + private static final MetricExporter INSTANCE = new NoopMetricExporter(); + + NoopMetricExporter() { + } + + static MetricExporter getInstance() { + return INSTANCE; + } + + + @Override + public CompletableResultCode export(Collection metrics) { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode flush() { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode shutdown() { + return CompletableResultCode.ofSuccess(); + } + + @Override + public AggregationTemporality getAggregationTemporality(InstrumentType instrumentType) { + return AggregationTemporalitySelector.alwaysCumulative().getAggregationTemporality(instrumentType); + } +} diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopSpanExporter.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopSpanExporter.java new file mode 100644 index 0000000..4a2378c --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopSpanExporter.java @@ -0,0 +1,32 @@ +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; + +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.logs.data.LogRecordData; +import io.opentelemetry.sdk.logs.export.LogRecordExporter; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.export.SpanExporter; + +import java.util.Collection; + +class NoopSpanExporter implements SpanExporter { + private static final SpanExporter INSTANCE = new NoopSpanExporter(); + + NoopSpanExporter() { + } + + static SpanExporter getInstance() { + return INSTANCE; + } + + public CompletableResultCode export(Collection logs) { + return CompletableResultCode.ofSuccess(); + } + + public CompletableResultCode flush() { + return CompletableResultCode.ofSuccess(); + } + + public CompletableResultCode shutdown() { + return CompletableResultCode.ofSuccess(); + } +} diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.logs.ConfigurableLogRecordExporterProvider b/cf-java-logging-support-opentelemetry-agent-extension/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.logs.ConfigurableLogRecordExporterProvider new file mode 100644 index 0000000..811c203 --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.logs.ConfigurableLogRecordExporterProvider @@ -0,0 +1 @@ +com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter.CloudLoggingLogsExporterProvider \ No newline at end of file diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider b/cf-java-logging-support-opentelemetry-agent-extension/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider new file mode 100644 index 0000000..b44bf5c --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider @@ -0,0 +1 @@ +com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter.CloudLoggingMetricsExporterProvider \ No newline at end of file diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider b/cf-java-logging-support-opentelemetry-agent-extension/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider new file mode 100644 index 0000000..68a755a --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider @@ -0,0 +1 @@ +com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter.CloudLoggingSpanExporterProvider \ No newline at end of file From 1be20571189847358395cfc60d556620976b3f58 Mon Sep 17 00:00:00 2001 From: Karsten Schnitter Date: Tue, 12 Dec 2023 14:53:23 +0100 Subject: [PATCH 2/6] Add Unit Tests and Refactor Prod Code Adds unit tests for all main parts of the new instrumentation. Checking cases of missing bindings and other configuration issues. Signed-off-by: Karsten Schnitter --- ...CloudLoggingBindingPropertiesSupplier.java | 37 +++-- .../ext/exporter/CloudLoggingCredentials.java | 23 ++- .../CloudLoggingLogsExporterProvider.java | 9 +- .../CloudLoggingMetricsExporterProvider.java | 13 +- .../CloudLoggingSpanExporterProvider.java | 14 +- .../ext/exporter/MultiMetricExporter.java | 22 ++- .../ext/exporter/NoopMetricExporter.java | 3 - .../agent/ext/exporter/NoopSpanExporter.java | 2 - ...dLoggingBindingPropertiesSupplierTest.java | 19 ++- .../exporter/CloudLoggingCredentialsTest.java | 97 +++++++++++++ .../CloudLoggingLogsExporterProviderTest.java | 103 +++++++++++++ ...oudLoggingMetricsExporterProviderTest.java | 103 +++++++++++++ .../CloudLoggingServicesProviderTest.java | 71 +++++++++ .../CloudLoggingSpanExporterProviderTest.java | 103 +++++++++++++ .../ext/exporter/MultiMetricExporterTest.java | 135 ++++++++++++++++++ .../agent/ext/exporter/PEMUtil.java | 20 +++ .../src/test/resources/certificate.crt | 21 +++ .../src/test/resources/certificate.pem | 21 +++ .../src/test/resources/csr.csr | 17 +++ .../src/test/resources/private.key | 28 ++++ .../src/test/resources/private.pem | 28 ++++ 21 files changed, 828 insertions(+), 61 deletions(-) create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingCredentialsTest.java create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingLogsExporterProviderTest.java create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingMetricsExporterProviderTest.java create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingServicesProviderTest.java create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingSpanExporterProviderTest.java create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/MultiMetricExporterTest.java create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/PEMUtil.java create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/certificate.crt create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/certificate.pem create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/csr.csr create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/private.key create mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/private.pem diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingBindingPropertiesSupplier.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingBindingPropertiesSupplier.java index 207f711..7a044e6 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingBindingPropertiesSupplier.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingBindingPropertiesSupplier.java @@ -17,20 +17,33 @@ public class CloudLoggingBindingPropertiesSupplier implements Supplier> { private static final Logger LOG = Logger.getLogger(CloudLoggingBindingPropertiesSupplier.class.getName()); + private static final String OTLP_ENDPOINT = "ingest-otlp-endpoint"; + private static final String OTLP_CLIENT_KEY = "ingest-otlp-key"; + private static final String OTLP_CLIENT_CERT = "ingest-otlp-cert"; + private static final String OTLP_SERVER_CERT = "server-ca"; private static final String CLOUD_LOGGING_LABEL = System.getProperty("com.sap.otel.extension.cloud-logging.label", "cloud-logging"); private static final String CLOUD_LOGGING_TAG = System.getProperty("com.sap.otel.extension.cloud-logging.tag", "Cloud Logging"); private static final String USER_PROVIDED_LABEL = "user-provided"; - public static final String OTLP_ENDPOINT = "ingest-otlp-endpoint"; - public static final String OTLP_CLIENT_KEY = "ingest-otlp-key"; - public static final String OTLP_CLIENT_CERT = "ingest-otlp-cert"; - public static final String OTLP_SERVER_CERT = "server-ca"; - private final CfEnv cfEnv; public CloudLoggingBindingPropertiesSupplier(CfEnv cfEnv) { this.cfEnv = cfEnv; } + private static boolean isBlank(String text) { + return text == null || text.trim().isEmpty(); + } + + private static File writeFile(String prefix, String suffix, String content) throws IOException { + File file = File.createTempFile(prefix, suffix); + file.deleteOnExit(); + try (FileWriter writer = new FileWriter(file)) { + writer.append(content); + LOG.fine("Created temporary file " + file.getAbsolutePath()); + } + return file; + } + /** * Scans service bindings, both managed and user-provided for Cloud Logging. * Managed services require the label "cloud-logging" to be considered. @@ -94,18 +107,4 @@ private Map createEndpointConfiguration(CfService svc) { } } - private static boolean isBlank(String text) { - return text == null || text.trim().isEmpty(); - } - - private static File writeFile(String prefix, String suffix, String content) throws IOException { - File file = File.createTempFile(prefix, suffix); - file.deleteOnExit(); - try (FileWriter writer = new FileWriter(file)) { - writer.append(content); - LOG.fine("Created temporary file " + file.getAbsolutePath()); - } - return file; - } - } diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingCredentials.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingCredentials.java index a023d3d..30dd39d 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingCredentials.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingCredentials.java @@ -9,6 +9,8 @@ class CloudLoggingCredentials { private static final Logger LOG = Logger.getLogger(CloudLoggingCredentials.class.getName()); + private static final Parser PARSER = new Parser(); + private static final String CRED_OTLP_ENDPOINT = "ingest-otlp-endpoint"; private static final String CRED_OTLP_CLIENT_KEY = "ingest-otlp-key"; private static final String CRED_OTLP_CLIENT_CERT = "ingest-otlp-cert"; @@ -24,13 +26,8 @@ class CloudLoggingCredentials { private CloudLoggingCredentials() { } - static CloudLoggingCredentials parseCredentials(CfCredentials cfCredentials) { - CloudLoggingCredentials parsed = new CloudLoggingCredentials(); - parsed.endpoint = CLOUD_LOGGING_ENDPOINT_PREFIX + cfCredentials.getString(CRED_OTLP_ENDPOINT); - parsed.clientKey = getPEMBytes(cfCredentials, CRED_OTLP_CLIENT_KEY); - parsed.clientCert = getPEMBytes(cfCredentials, CRED_OTLP_CLIENT_CERT); - parsed.serverCert = getPEMBytes(cfCredentials, CRED_OTLP_SERVER_CERT); - return parsed; + static CloudLoggingCredentials.Parser parser() { + return PARSER; } private static byte[] getPEMBytes(CfCredentials credentials, String key) { @@ -84,4 +81,16 @@ public byte[] getClientCert() { public byte[] getServerCert() { return serverCert; } + + static class Parser { + CloudLoggingCredentials parse(CfCredentials cfCredentials) { + CloudLoggingCredentials parsed = new CloudLoggingCredentials(); + String rawEndpoint = cfCredentials.getString(CRED_OTLP_ENDPOINT); + parsed.endpoint = isBlank(rawEndpoint) ? null : CLOUD_LOGGING_ENDPOINT_PREFIX + rawEndpoint; + parsed.clientKey = getPEMBytes(cfCredentials, CRED_OTLP_CLIENT_KEY); + parsed.clientCert = getPEMBytes(cfCredentials, CRED_OTLP_CLIENT_CERT); + parsed.serverCert = getPEMBytes(cfCredentials, CRED_OTLP_SERVER_CERT); + return parsed; + } + } } diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingLogsExporterProvider.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingLogsExporterProvider.java index 33159b2..2d86135 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingLogsExporterProvider.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingLogsExporterProvider.java @@ -11,7 +11,6 @@ import java.time.Duration; import java.util.List; -import java.util.Objects; import java.util.function.Function; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -22,13 +21,15 @@ public class CloudLoggingLogsExporterProvider implements ConfigurableLogRecordEx private static final Logger LOG = Logger.getLogger(CloudLoggingLogsExporterProvider.class.getName()); private final Function> servicesProvider; + private final CloudLoggingCredentials.Parser credentialParser; public CloudLoggingLogsExporterProvider() { - this(config -> new CloudLoggingServicesProvider(config, new CfEnv()).get()); + this(config -> new CloudLoggingServicesProvider(config, new CfEnv()).get(), CloudLoggingCredentials.parser()); } - public CloudLoggingLogsExporterProvider(Function> serviceProvider) { + CloudLoggingLogsExporterProvider(Function> serviceProvider, CloudLoggingCredentials.Parser credentialParser) { this.servicesProvider = serviceProvider; + this.credentialParser = credentialParser; } private static String getCompression(ConfigProperties config) { @@ -57,7 +58,7 @@ public LogRecordExporter createExporter(ConfigProperties config) { private LogRecordExporter createExporter(ConfigProperties config, CfService service) { LOG.info("Creating logs exporter for service binding " + service.getName() + " (" + service.getLabel() + ")"); - CloudLoggingCredentials credentials = CloudLoggingCredentials.parseCredentials(service.getCredentials()); + CloudLoggingCredentials credentials = credentialParser.parse(service.getCredentials()); if (!credentials.validate()) { return NoopLogRecordExporter.getInstance(); } diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingMetricsExporterProvider.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingMetricsExporterProvider.java index 4f4da25..d9e0dd1 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingMetricsExporterProvider.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingMetricsExporterProvider.java @@ -12,13 +12,13 @@ import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector; import io.opentelemetry.sdk.metrics.export.MetricExporter; import io.opentelemetry.sdk.metrics.internal.aggregator.AggregationUtil; +import io.pivotal.cfenv.core.CfCredentials; import io.pivotal.cfenv.core.CfEnv; import io.pivotal.cfenv.core.CfService; import java.time.Duration; import java.util.List; import java.util.Locale; -import java.util.Objects; import java.util.function.Function; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -31,13 +31,15 @@ public class CloudLoggingMetricsExporterProvider implements ConfigurableMetricEx private static final Logger LOG = Logger.getLogger(CloudLoggingMetricsExporterProvider.class.getName()); private final Function> servicesProvider; + private final CloudLoggingCredentials.Parser credentialParser; public CloudLoggingMetricsExporterProvider() { - this(config -> new CloudLoggingServicesProvider(config, new CfEnv()).get()); + this(config -> new CloudLoggingServicesProvider(config, new CfEnv()).get(), CloudLoggingCredentials.parser()); } - public CloudLoggingMetricsExporterProvider(Function> serviceProvider) { + CloudLoggingMetricsExporterProvider(Function> serviceProvider, CloudLoggingCredentials.Parser credentialParser) { this.servicesProvider = serviceProvider; + this.credentialParser = credentialParser; } private static String getCompression(ConfigProperties config) { @@ -99,12 +101,13 @@ public MetricExporter createExporter(ConfigProperties config) { .map(svc -> createExporter(config, svc)) .filter(exp -> !(exp instanceof NoopMetricExporter)) .collect(Collectors.toList()); - return new MultiMetricExporter(getAggregationTemporalitySelector(config), getDefaultAggregationSelector(config), exporters); + return MultiMetricExporter.composite(exporters, getAggregationTemporalitySelector(config), getDefaultAggregationSelector(config)); } private MetricExporter createExporter(ConfigProperties config, CfService service) { LOG.info("Creating metrics exporter for service binding " + service.getName() + " (" + service.getLabel() + ")"); - CloudLoggingCredentials credentials = CloudLoggingCredentials.parseCredentials(service.getCredentials()); + CfCredentials cfCredentials = service.getCredentials(); + CloudLoggingCredentials credentials = credentialParser.parse(cfCredentials); if (!credentials.validate()) { return NoopMetricExporter.getInstance(); } diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingSpanExporterProvider.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingSpanExporterProvider.java index a58af2d..c3fa87c 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingSpanExporterProvider.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingSpanExporterProvider.java @@ -1,20 +1,17 @@ package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; -import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; -import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider; import io.opentelemetry.sdk.common.export.RetryPolicy; -import io.opentelemetry.sdk.logs.export.LogRecordExporter; import io.opentelemetry.sdk.trace.export.SpanExporter; +import io.pivotal.cfenv.core.CfCredentials; import io.pivotal.cfenv.core.CfEnv; import io.pivotal.cfenv.core.CfService; import java.time.Duration; import java.util.List; -import java.util.Objects; import java.util.function.Function; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -25,13 +22,15 @@ public class CloudLoggingSpanExporterProvider implements ConfigurableSpanExporte private static final Logger LOG = Logger.getLogger(CloudLoggingSpanExporterProvider.class.getName()); private final Function> servicesProvider; + private final CloudLoggingCredentials.Parser credentialParser; public CloudLoggingSpanExporterProvider() { - this(config -> new CloudLoggingServicesProvider(config, new CfEnv()).get()); + this(config -> new CloudLoggingServicesProvider(config, new CfEnv()).get(), CloudLoggingCredentials.parser()); } - public CloudLoggingSpanExporterProvider(Function> serviceProvider) { + CloudLoggingSpanExporterProvider(Function> serviceProvider, CloudLoggingCredentials.Parser credentialParser) { this.servicesProvider = serviceProvider; + this.credentialParser = credentialParser; } private static String getCompression(ConfigProperties config) { @@ -60,7 +59,8 @@ public SpanExporter createExporter(ConfigProperties config) { private SpanExporter createExporter(ConfigProperties config, CfService service) { LOG.info("Creating span exporter for service binding " + service.getName() + " (" + service.getLabel() + ")"); - CloudLoggingCredentials credentials = CloudLoggingCredentials.parseCredentials(service.getCredentials()); + CfCredentials cfCredentials = service.getCredentials(); + CloudLoggingCredentials credentials = credentialParser.parse(cfCredentials); if (!credentials.validate()) { return NoopSpanExporter.getInstance(); } diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/MultiMetricExporter.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/MultiMetricExporter.java index 9074f28..47d4031 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/MultiMetricExporter.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/MultiMetricExporter.java @@ -24,14 +24,30 @@ class MultiMetricExporter implements MetricExporter { private final DefaultAggregationSelector defaultAggregationSelector; private final List metricExporters; - MultiMetricExporter(AggregationTemporalitySelector aggregationTemporalitySelector, - DefaultAggregationSelector defaultAggregationSelector, - List metricExporters) { + private MultiMetricExporter(AggregationTemporalitySelector aggregationTemporalitySelector, + DefaultAggregationSelector defaultAggregationSelector, + List metricExporters) { this.aggregationTemporalitySelector = aggregationTemporalitySelector; this.defaultAggregationSelector = defaultAggregationSelector; this.metricExporters = metricExporters; } + static MetricExporter composite(List metricExporters, AggregationTemporalitySelector aggregationTemporalitySelector, DefaultAggregationSelector defaultAggregationSelector) { + if (metricExporters == null || metricExporters.isEmpty()) { + return NoopMetricExporter.getInstance(); + } + if (metricExporters.size() == 1) { + return metricExporters.get(0); + } + if (aggregationTemporalitySelector == null) { + aggregationTemporalitySelector = metricExporters.get(0); + } + if (defaultAggregationSelector == null) { + defaultAggregationSelector = metricExporters.get(0); + } + return new MultiMetricExporter(aggregationTemporalitySelector, defaultAggregationSelector, metricExporters); + } + public CompletableResultCode export(Collection metrics) { List results = new ArrayList<>(metricExporters.size()); for (MetricExporter metricExporter : metricExporters) { diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopMetricExporter.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopMetricExporter.java index 862fed5..0a53be8 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopMetricExporter.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopMetricExporter.java @@ -1,7 +1,6 @@ package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.logs.export.LogRecordExporter; import io.opentelemetry.sdk.metrics.InstrumentType; import io.opentelemetry.sdk.metrics.data.AggregationTemporality; import io.opentelemetry.sdk.metrics.data.MetricData; @@ -9,8 +8,6 @@ import io.opentelemetry.sdk.metrics.export.MetricExporter; import java.util.Collection; -import java.util.logging.Level; -import java.util.logging.Logger; public class NoopMetricExporter implements MetricExporter { diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopSpanExporter.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopSpanExporter.java index 4a2378c..c3b073b 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopSpanExporter.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/NoopSpanExporter.java @@ -1,8 +1,6 @@ package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.logs.data.LogRecordData; -import io.opentelemetry.sdk.logs.export.LogRecordExporter; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.export.SpanExporter; diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingBindingPropertiesSupplierTest.java b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingBindingPropertiesSupplierTest.java index 8a92971..9492572 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingBindingPropertiesSupplierTest.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingBindingPropertiesSupplierTest.java @@ -10,10 +10,7 @@ import java.util.stream.Collectors; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasEntry; -import static org.hamcrest.Matchers.hasKey; -import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertTrue; public class CloudLoggingBindingPropertiesSupplierTest { @@ -22,6 +19,13 @@ public class CloudLoggingBindingPropertiesSupplierTest { private static final String USER_PROVIDED_VALID = "{\"label\":\"user-provided\", \"name\":\"test-name\", \"tags\":[\"Cloud Logging\"], \"credentials\":" + VALID_CREDENTIALS + "}"; private static final String MANAGED_VALID = "{\"label\":\"cloud-logging\", \"name\":\"test-name\", \"tags\":[\"Cloud Logging\"], \"credentials\":" + VALID_CREDENTIALS + "}"; + private static void assertFileContent(String expected, String filename) throws IOException { + String contents = Files.readAllLines(Paths.get(filename)) + .stream() + .collect(Collectors.joining("\n")); + assertThat(contents, is(equalTo(expected))); + } + @Test public void emptyWithoutBindings() { CfEnv cfEnv = new CfEnv("", ""); @@ -114,11 +118,4 @@ public void emptyWithoutServerCert() { Map properties = propertiesSupplier.get(); assertTrue(properties.isEmpty()); } - - private static void assertFileContent(String expected, String filename) throws IOException { - String contents = Files.readAllLines(Paths.get(filename)) - .stream() - .collect(Collectors.joining("\n")); - assertThat(contents, is(equalTo(expected))); - } } \ No newline at end of file diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingCredentialsTest.java b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingCredentialsTest.java new file mode 100644 index 0000000..c79961a --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingCredentialsTest.java @@ -0,0 +1,97 @@ +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; + +import io.pivotal.cfenv.core.CfCredentials; +import org.jetbrains.annotations.NotNull; +import org.junit.Test; + +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class CloudLoggingCredentialsTest { + + private static final String VALID_CLIENT_CERT = "-----BEGIN CERTIFICATE-----\n" + + "Base-64-Encoded Certificate\n" + + "-----END CERTIFICATE-----\n"; + + private static final String VALID_CLIENT_KEY = "-----BEGIN PRIVATE KEY-----\n" + + "Base-64-Encoded Private Key\n" + + "-----END PRIVATE KEY-----\n"; + + private static final String VALID_SERVER_CERT = "-----BEGIN CERTIFICATE-----\n" + + "Base-64-Encoded Server Certificate\n" + + "-----END CERTIFICATE-----\n"; + + private static final CloudLoggingCredentials.Parser PARSER = CloudLoggingCredentials.parser(); + + @NotNull + private static Map getValidCredData() { + Map credData = new HashMap<>(); + credData.put("ingest-otlp-endpoint", "test-endpoint"); + credData.put("ingest-otlp-cert", VALID_CLIENT_CERT); + credData.put("ingest-otlp-key", VALID_CLIENT_KEY); + credData.put("server-ca", VALID_SERVER_CERT); + return credData; + } + + @Test + public void validCredentials() { + Map credData = getValidCredData(); + CfCredentials cfCredentials = new CfCredentials(credData); + CloudLoggingCredentials credentials = PARSER.parse(cfCredentials); + assertTrue("Credentials should be valid", credentials.validate()); + } + + @Test + public void missingEndpoint() { + Map credData = getValidCredData(); + credData.remove("ingest-otlp-endpoint"); + CfCredentials cfCredentials = new CfCredentials(credData); + CloudLoggingCredentials credentials = PARSER.parse(cfCredentials); + assertFalse("Credentials should be invalid", credentials.validate()); + } + + @Test + public void missingClientKey() { + Map credData = getValidCredData(); + credData.remove("ingest-otlp-key"); + CfCredentials cfCredentials = new CfCredentials(credData); + CloudLoggingCredentials credentials = PARSER.parse(cfCredentials); + assertFalse("Credentials should be invalid", credentials.validate()); + } + + @Test + public void missingClientCert() { + Map credData = getValidCredData(); + credData.remove("ingest-otlp-cert"); + CfCredentials cfCredentials = new CfCredentials(credData); + CloudLoggingCredentials credentials = PARSER.parse(cfCredentials); + assertFalse("Credentials should be invalid", credentials.validate()); + } + + @Test + public void missingServerCert() { + Map credData = getValidCredData(); + credData.remove("server-ca"); + CfCredentials cfCredentials = new CfCredentials(credData); + CloudLoggingCredentials credentials = PARSER.parse(cfCredentials); + assertFalse("Credentials should be invalid", credentials.validate()); + } + + @Test + public void parsesCorrectly() { + Map credData = getValidCredData(); + CfCredentials cfCredentials = new CfCredentials(credData); + CloudLoggingCredentials credentials = PARSER.parse(cfCredentials); + assertThat(credentials.getEndpoint(), equalTo("https://test-endpoint")); + assertThat(new String(credentials.getClientCert(), StandardCharsets.UTF_8), equalTo("-----BEGIN CERTIFICATE-----\nBase-64-Encoded Certificate\n-----END CERTIFICATE-----")); + assertThat(new String(credentials.getClientKey(), StandardCharsets.UTF_8), equalTo("-----BEGIN PRIVATE KEY-----\nBase-64-Encoded Private Key\n-----END PRIVATE KEY-----")); + assertThat(new String(credentials.getServerCert(), StandardCharsets.UTF_8), equalTo("-----BEGIN CERTIFICATE-----\nBase-64-Encoded Server Certificate\n-----END CERTIFICATE-----")); + } + +} diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingLogsExporterProviderTest.java b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingLogsExporterProviderTest.java new file mode 100644 index 0000000..a20afe7 --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingLogsExporterProviderTest.java @@ -0,0 +1,103 @@ +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; + +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.logs.ConfigurableLogRecordExporterProvider; +import io.opentelemetry.sdk.logs.export.LogRecordExporter; +import io.pivotal.cfenv.core.CfService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; + +import java.io.IOException; +import java.util.Collections; +import java.util.ServiceLoader; +import java.util.function.Function; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class CloudLoggingLogsExporterProviderTest { + + @Mock + private Function> servicesProvider; + + @Mock + private CloudLoggingCredentials.Parser credentialParser; + + @Mock + private ConfigProperties config; + + @InjectMocks + private CloudLoggingLogsExporterProvider exporterProvider; + + @Before + public void setUp() { + when(config.getString(any(), any())).thenAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + return invocation.getArguments()[1]; + } + }); + + } + + @Test + public void canLoadViaSPI() { + ServiceLoader loader = ServiceLoader.load(ConfigurableLogRecordExporterProvider.class); + Stream providers = StreamSupport.stream(loader.spliterator(), false); + assertTrue(CloudLoggingLogsExporterProvider.class.getName() + " not loaded via SPI", + providers.anyMatch(p -> p instanceof CloudLoggingLogsExporterProvider)); + } + + @Test + public void registersNoopExporterWithoutBindings() { + when(servicesProvider.apply(config)).thenReturn(Stream.empty()); + LogRecordExporter exporter = exporterProvider.createExporter(config); + assertThat(exporter, is(notNullValue())); + assertThat(exporter.toString(), containsString("Noop")); + } + + @Test + public void registersNoopExporterWithInvalidBindings() { + CfService genericCfService = new CfService(Collections.emptyMap()); + when(servicesProvider.apply(config)).thenReturn(Stream.of(genericCfService)); + CloudLoggingCredentials cloudLoggingCredentials = mock(CloudLoggingCredentials.class); + when(credentialParser.parse(any())).thenReturn(cloudLoggingCredentials); + when(cloudLoggingCredentials.validate()).thenReturn(false); + LogRecordExporter exporter = exporterProvider.createExporter(config); + assertThat(exporter, is(notNullValue())); + assertThat(exporter.toString(), containsString("Noop")); + } + + @Test + public void registersExportersWithValidBindings() throws IOException { + CfService genericCfService = new CfService(Collections.emptyMap()); + CfService cloudLoggingService = new CfService(Collections.emptyMap()); + when(servicesProvider.apply(config)).thenReturn(Stream.of(genericCfService, cloudLoggingService)); + CloudLoggingCredentials invalidCredentials = mock(CloudLoggingCredentials.class); + when(invalidCredentials.validate()).thenReturn(false); + CloudLoggingCredentials validCredentials = mock(CloudLoggingCredentials.class); + when(validCredentials.validate()).thenReturn(true); + when(validCredentials.getEndpoint()).thenReturn("https://otlp-example.sap"); + when(validCredentials.getClientCert()).thenReturn(PEMUtil.read("certificate.pem")); + when(validCredentials.getClientKey()).thenReturn(PEMUtil.read("private.pem")); + when(validCredentials.getServerCert()).thenReturn(PEMUtil.read("certificate.pem")); + when(credentialParser.parse(any())).thenReturn(invalidCredentials).thenReturn(validCredentials); + LogRecordExporter exporter = exporterProvider.createExporter(config); + assertThat(exporter, is(notNullValue())); + assertThat(exporter.toString(), both(containsString("OtlpGrpcLogRecordExporter")).and(containsString("https://otlp-example.sap"))); + } + +} \ No newline at end of file diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingMetricsExporterProviderTest.java b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingMetricsExporterProviderTest.java new file mode 100644 index 0000000..6eccff8 --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingMetricsExporterProviderTest.java @@ -0,0 +1,103 @@ +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; + +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider; +import io.opentelemetry.sdk.metrics.export.MetricExporter; +import io.pivotal.cfenv.core.CfService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; + +import java.io.IOException; +import java.util.Collections; +import java.util.ServiceLoader; +import java.util.function.Function; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class CloudLoggingMetricsExporterProviderTest { + + @Mock + private Function> servicesProvider; + + @Mock + private CloudLoggingCredentials.Parser credentialParser; + + @Mock + private ConfigProperties config; + + @InjectMocks + private CloudLoggingMetricsExporterProvider exporterProvider; + + @Before + public void setUp() { + when(config.getString(any(), any())).thenAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + return invocation.getArguments()[1]; + } + }); + + } + + @Test + public void canLoadViaSPI() { + ServiceLoader loader = ServiceLoader.load(ConfigurableMetricExporterProvider.class); + Stream providers = StreamSupport.stream(loader.spliterator(), false); + assertTrue(CloudLoggingMetricsExporterProvider.class.getName() + " not loaded via SPI", + providers.anyMatch(p -> p instanceof CloudLoggingMetricsExporterProvider)); + } + + @Test + public void registersNoopExporterWithoutBindings() { + when(servicesProvider.apply(config)).thenReturn(Stream.empty()); + MetricExporter exporter = exporterProvider.createExporter(config); + assertThat(exporter, is(notNullValue())); + assertThat(exporter.toString(), containsString("Noop")); + } + + @Test + public void registersNoopExporterWithInvalidBindings() { + CfService genericCfService = new CfService(Collections.emptyMap()); + when(servicesProvider.apply(config)).thenReturn(Stream.of(genericCfService)); + CloudLoggingCredentials cloudLoggingCredentials = mock(CloudLoggingCredentials.class); + when(credentialParser.parse(any())).thenReturn(cloudLoggingCredentials); + when(cloudLoggingCredentials.validate()).thenReturn(false); + MetricExporter exporter = exporterProvider.createExporter(config); + assertThat(exporter, is(notNullValue())); + assertThat(exporter.toString(), containsString("Noop")); + } + + @Test + public void registersExportersWithValidBindings() throws IOException { + CfService genericCfService = new CfService(Collections.emptyMap()); + CfService cloudLoggingService = new CfService(Collections.emptyMap()); + when(servicesProvider.apply(config)).thenReturn(Stream.of(genericCfService, cloudLoggingService)); + CloudLoggingCredentials invalidCredentials = mock(CloudLoggingCredentials.class); + when(invalidCredentials.validate()).thenReturn(false); + CloudLoggingCredentials validCredentials = mock(CloudLoggingCredentials.class); + when(validCredentials.validate()).thenReturn(true); + when(validCredentials.getEndpoint()).thenReturn("https://otlp-example.sap"); + when(validCredentials.getClientCert()).thenReturn(PEMUtil.read("certificate.pem")); + when(validCredentials.getClientKey()).thenReturn(PEMUtil.read("private.pem")); + when(validCredentials.getServerCert()).thenReturn(PEMUtil.read("certificate.pem")); + when(credentialParser.parse(any())).thenReturn(invalidCredentials).thenReturn(validCredentials); + MetricExporter exporter = exporterProvider.createExporter(config); + assertThat(exporter, is(notNullValue())); + assertThat(exporter.toString(), both(containsString("OtlpGrpcMetricExporter")).and(containsString("https://otlp-example.sap"))); + } + +} \ No newline at end of file diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingServicesProviderTest.java b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingServicesProviderTest.java new file mode 100644 index 0000000..ddfa313 --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingServicesProviderTest.java @@ -0,0 +1,71 @@ +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; + +import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; +import io.pivotal.cfenv.core.CfEnv; +import io.pivotal.cfenv.core.CfService; +import org.junit.Test; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasSize; + +public class CloudLoggingServicesProviderTest { + + private static final String DEFAULT_VCAP_APPLICATION = "{}"; + private static final String DEFAULT_VCAP_SERVICES = "{" + + "\"cloud-logging\":[" + + "{\"label\":\"cloud-logging\", \"tags\":[\"Cloud Logging\"],\"name\":\"managed-service1\"}," + + "{\"label\":\"cloud-logging\", \"tags\":[\"Cloud Logging\"],\"name\":\"managed-service2\"}" + + "]," + + "\"not-cloud-logging\":[" + + "{\"label\":\"not-cloud-logging\", \"tags\":[\"Cloud Logging\"],\"name\":\"managed-other\"}" + + "]," + + "\"user-provided\":[" + + "{\"label\":\"cloud-logging\", \"tags\":[\"Cloud Logging\"],\"name\":\"ups-cloud-logging\"}," + + "{\"label\":\"cloud-logging\", \"tags\":[\"NOT Cloud Logging\"],\"name\":\"ups-other\"}" + + "]}"; + + @Test + public void defaultLabelsAndTags() { + DefaultConfigProperties emptyProperties = DefaultConfigProperties.createFromMap(Collections.emptyMap()); + CfEnv cfEnv = new CfEnv(DEFAULT_VCAP_APPLICATION, DEFAULT_VCAP_SERVICES); + CloudLoggingServicesProvider servicesProvider = new CloudLoggingServicesProvider(emptyProperties, cfEnv); + List serviceNames = servicesProvider.get().map(CfService::getName).collect(Collectors.toList()); + assertThat(serviceNames, hasSize(3)); + assertThat(serviceNames, hasItem("managed-service1")); + assertThat(serviceNames, hasItem("managed-service2")); + assertThat(serviceNames, hasItem("ups-cloud-logging")); + } + + @Test + public void customLabel() { + Map properties = new HashMap<>(); + properties.put("otel.javaagent.extension.sap.cf.binding.cloud-logging.label", "not-cloud-logging"); + properties.put("otel.javaagent.extension.sap.cf.binding.user-provided.label", "unknown-label"); + DefaultConfigProperties emptyProperties = DefaultConfigProperties.createFromMap(properties); + CfEnv cfEnv = new CfEnv(DEFAULT_VCAP_APPLICATION, DEFAULT_VCAP_SERVICES); + CloudLoggingServicesProvider servicesProvider = new CloudLoggingServicesProvider(emptyProperties, cfEnv); + List serviceNames = servicesProvider.get().map(CfService::getName).collect(Collectors.toList()); + assertThat(serviceNames, hasSize(1)); + assertThat(serviceNames, hasItem("managed-other")); + } + + @Test + public void customTag() { + Map properties = new HashMap<>(); + properties.put("otel.javaagent.extension.sap.cf.binding.cloud-logging.tag", "NOT Cloud Logging"); + DefaultConfigProperties emptyProperties = DefaultConfigProperties.createFromMap(properties); + CfEnv cfEnv = new CfEnv(DEFAULT_VCAP_APPLICATION, DEFAULT_VCAP_SERVICES); + CloudLoggingServicesProvider servicesProvider = new CloudLoggingServicesProvider(emptyProperties, cfEnv); + List serviceNames = servicesProvider.get().map(CfService::getName).collect(Collectors.toList()); + assertThat(serviceNames, hasSize(1)); + assertThat(serviceNames, hasItem("ups-other")); + } + +} \ No newline at end of file diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingSpanExporterProviderTest.java b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingSpanExporterProviderTest.java new file mode 100644 index 0000000..b1057c4 --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingSpanExporterProviderTest.java @@ -0,0 +1,103 @@ +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; + +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import io.pivotal.cfenv.core.CfService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; + +import java.io.IOException; +import java.util.Collections; +import java.util.ServiceLoader; +import java.util.function.Function; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class CloudLoggingSpanExporterProviderTest { + + @Mock + private Function> servicesProvider; + + @Mock + private CloudLoggingCredentials.Parser credentialParser; + + @Mock + private ConfigProperties config; + + @InjectMocks + private CloudLoggingSpanExporterProvider exporterProvider; + + @Before + public void setUp() { + when(config.getString(any(), any())).thenAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + return invocation.getArguments()[1]; + } + }); + + } + + @Test + public void canLoadViaSPI() { + ServiceLoader loader = ServiceLoader.load(ConfigurableSpanExporterProvider.class); + Stream providers = StreamSupport.stream(loader.spliterator(), false); + assertTrue(CloudLoggingSpanExporterProvider.class.getName() + " not loaded via SPI", + providers.anyMatch(p -> p instanceof CloudLoggingSpanExporterProvider)); + } + + @Test + public void registersNoopExporterWithoutBindings() { + when(servicesProvider.apply(config)).thenReturn(Stream.empty()); + SpanExporter exporter = exporterProvider.createExporter(config); + assertThat(exporter, is(notNullValue())); + assertThat(exporter.toString(), containsString("Noop")); + } + + @Test + public void registersNoopExporterWithInvalidBindings() { + CfService genericCfService = new CfService(Collections.emptyMap()); + when(servicesProvider.apply(config)).thenReturn(Stream.of(genericCfService)); + CloudLoggingCredentials cloudLoggingCredentials = mock(CloudLoggingCredentials.class); + when(credentialParser.parse(any())).thenReturn(cloudLoggingCredentials); + when(cloudLoggingCredentials.validate()).thenReturn(false); + SpanExporter exporter = exporterProvider.createExporter(config); + assertThat(exporter, is(notNullValue())); + assertThat(exporter.toString(), containsString("Noop")); + } + + @Test + public void registersExportersWithValidBindings() throws IOException { + CfService genericCfService = new CfService(Collections.emptyMap()); + CfService cloudLoggingService = new CfService(Collections.emptyMap()); + when(servicesProvider.apply(config)).thenReturn(Stream.of(genericCfService, cloudLoggingService)); + CloudLoggingCredentials invalidCredentials = mock(CloudLoggingCredentials.class); + when(invalidCredentials.validate()).thenReturn(false); + CloudLoggingCredentials validCredentials = mock(CloudLoggingCredentials.class); + when(validCredentials.validate()).thenReturn(true); + when(validCredentials.getEndpoint()).thenReturn("https://otlp-example.sap"); + when(validCredentials.getClientCert()).thenReturn(PEMUtil.read("certificate.pem")); + when(validCredentials.getClientKey()).thenReturn(PEMUtil.read("private.pem")); + when(validCredentials.getServerCert()).thenReturn(PEMUtil.read("certificate.pem")); + when(credentialParser.parse(any())).thenReturn(invalidCredentials).thenReturn(validCredentials); + SpanExporter exporter = exporterProvider.createExporter(config); + assertThat(exporter, is(notNullValue())); + assertThat(exporter.toString(), both(containsString("OtlpGrpcSpanExporter")).and(containsString("https://otlp-example.sap"))); + } + +} \ No newline at end of file diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/MultiMetricExporterTest.java b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/MultiMetricExporterTest.java new file mode 100644 index 0000000..778ab10 --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/MultiMetricExporterTest.java @@ -0,0 +1,135 @@ +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; + +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.metrics.InstrumentType; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; +import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector; +import io.opentelemetry.sdk.metrics.export.MetricExporter; +import org.junit.Test; + +import java.util.Collection; +import java.util.Collections; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.*; + +public class MultiMetricExporterTest { + + @Test + public void createsNoopExporterOnNullExporterList() { + assertThat(MultiMetricExporter.composite(emptyList(), null, null), is(instanceOf(NoopMetricExporter.class))); + } + + @Test + public void createsNoopExporterOnEmptyExporterList() { + assertThat(MultiMetricExporter.composite(emptyList(), null, null), is(instanceOf(NoopMetricExporter.class))); + } + + @Test + public void returnsSingleExporterOnOneEntryExporterList() { + MetricExporter exporter = mock(MetricExporter.class); + assertThat(MultiMetricExporter.composite(singletonList(exporter), null, null), is(exporter)); + } + + @Test + public void delegatesExport() { + Collection metrics = Collections.emptyList(); + MetricExporter exporter1 = mock(MetricExporter.class); + when(exporter1.export(metrics)).thenReturn(CompletableResultCode.ofSuccess()); + MetricExporter exporter2 = mock(MetricExporter.class); + when(exporter2.export(metrics)).thenReturn(CompletableResultCode.ofSuccess()); + + MetricExporter metricExporter = MultiMetricExporter.composite(asList(exporter1, exporter2), null, null); + metricExporter.export(metrics); + + verify(exporter1).export(metrics); + verify(exporter2).export(metrics); + } + + + @Test + public void delegatesFlush() { + MetricExporter exporter1 = mock(MetricExporter.class); + when(exporter1.flush()).thenReturn(CompletableResultCode.ofSuccess()); + MetricExporter exporter2 = mock(MetricExporter.class); + when(exporter2.flush()).thenReturn(CompletableResultCode.ofSuccess()); + + MetricExporter metricExporter = MultiMetricExporter.composite(asList(exporter1, exporter2), null, null); + metricExporter.flush(); + + verify(exporter1).flush(); + verify(exporter2).flush(); + } + + + @Test + public void delegatesShutdwon() { + MetricExporter exporter1 = mock(MetricExporter.class); + when(exporter1.shutdown()).thenReturn(CompletableResultCode.ofSuccess()); + MetricExporter exporter2 = mock(MetricExporter.class); + when(exporter2.shutdown()).thenReturn(CompletableResultCode.ofSuccess()); + + MetricExporter metricExporter = MultiMetricExporter.composite(asList(exporter1, exporter2), null, null); + metricExporter.shutdown(); + + verify(exporter1).shutdown(); + verify(exporter2).shutdown(); + } + + @Test + public void delegatesAggregationTemporality() { + MetricExporter exporter1 = mock(MetricExporter.class); + MetricExporter exporter2 = mock(MetricExporter.class); + + AggregationTemporalitySelector aggregationTemporalitySelector = mock(AggregationTemporalitySelector.class); + + MetricExporter metricExporter = MultiMetricExporter.composite(asList(exporter1, exporter2), aggregationTemporalitySelector, null); + metricExporter.getAggregationTemporality(InstrumentType.OBSERVABLE_GAUGE); + + verify(aggregationTemporalitySelector).getAggregationTemporality(InstrumentType.OBSERVABLE_GAUGE); + } + + @Test + public void delegatesDefaultAggregation() { + MetricExporter exporter1 = mock(MetricExporter.class); + MetricExporter exporter2 = mock(MetricExporter.class); + + DefaultAggregationSelector defaultAggregationSelector = mock(DefaultAggregationSelector.class); + + MetricExporter metricExporter = MultiMetricExporter.composite(asList(exporter1, exporter2), null, defaultAggregationSelector); + metricExporter.getDefaultAggregation(InstrumentType.OBSERVABLE_GAUGE); + + verify(defaultAggregationSelector).getDefaultAggregation(InstrumentType.OBSERVABLE_GAUGE); + } + + @Test + public void delegatesAggregationTemporalityToFirstExporterIfNoExplicitAggregation() { + MetricExporter exporter1 = mock(MetricExporter.class); + MetricExporter exporter2 = mock(MetricExporter.class); + + MetricExporter metricExporter = MultiMetricExporter.composite(asList(exporter1, exporter2), null, null); + + metricExporter.getAggregationTemporality(InstrumentType.OBSERVABLE_GAUGE); + + verify(exporter1).getAggregationTemporality(InstrumentType.OBSERVABLE_GAUGE); + } + + @Test + public void delegatesDefaultAggregationToFirstExporterIfNoExplicitAggregation() { + MetricExporter exporter1 = mock(MetricExporter.class); + MetricExporter exporter2 = mock(MetricExporter.class); + + MetricExporter metricExporter = MultiMetricExporter.composite(asList(exporter1, exporter2), null, null); + + metricExporter.getDefaultAggregation(InstrumentType.OBSERVABLE_GAUGE); + + verify(exporter1).getDefaultAggregation(InstrumentType.OBSERVABLE_GAUGE); + } + +} \ No newline at end of file diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/PEMUtil.java b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/PEMUtil.java new file mode 100644 index 0000000..896ab21 --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/PEMUtil.java @@ -0,0 +1,20 @@ +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; + +import org.jetbrains.annotations.NotNull; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.stream.Collectors; + +class PEMUtil { + @NotNull + static byte[] read(String resourceName) throws IOException { + try (InputStream is = PEMUtil.class.getClassLoader().getResourceAsStream(resourceName)) { + if (is == null) { + throw new FileNotFoundException("Resource " + resourceName + " not found."); + } + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + return reader.lines().collect(Collectors.joining("\n")).getBytes(StandardCharsets.UTF_8); + } + } +} diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/certificate.crt b/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/certificate.crt new file mode 100644 index 0000000..f243434 --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/certificate.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDYzCCAksCFFfxHrrOeFLc3SuetPGuhqfFDBZOMA0GCSqGSIb3DQEBCwUAMG4x +CzAJBgNVBAYTAkRFMQ0wCwYDVQQIDARUZXN0MQ0wCwYDVQQHDARUZXN0MRAwDgYD +VQQKDAdUZXN0aW5nMQ0wCwYDVQQLDARUZXN0MSAwHgYDVQQDDBdjZi1qYXZhLWxv +Z2dpbmctc3VwcG9ydDAeFw0yMzEyMTQwNzA3MjJaFw0yNDEyMTMwNzA3MjJaMG4x +CzAJBgNVBAYTAkRFMQ0wCwYDVQQIDARUZXN0MQ0wCwYDVQQHDARUZXN0MRAwDgYD +VQQKDAdUZXN0aW5nMQ0wCwYDVQQLDARUZXN0MSAwHgYDVQQDDBdjZi1qYXZhLWxv +Z2dpbmctc3VwcG9ydDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK+V +L9twfgJODNYTAFgTcPK4D33DSrvxoj2KT6ddmC369xwioXTOXQtxTvzP9ypaW8D3 +rmqVQOYYj2L+2VvncEiBCXuaGb0rdaNYbOnuMdFBLbtWXlPFgVJR5js9zsxupANd +wFIYP6uFlhulyTXLBHF0tVTrhCoVdERxeF0/DUAyVid87ZVngqp+MFIZfFOKaflq +0iltypcE15nXmiIUQ3Ztf0pVgP34mRx5sE0Hz6hFObj/Yv09yq2UpuZ5gOPi86J1 +V9MimVLscsZ1oIfuPAtcAcDUc2ARaUpJHjVoHugUYKCg2pHeitAtCe9+EVdmHUTw +aqcYNPn6cQxO2c8nSFkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAKB/tE6wdl2Je +zZAyj622wEFZI73m8RjADUsa4amiox1D4pC/xUvI6N7JInvH4ty98Z25ZMv9GlBx +pwb8Arq5qR+g5HvH7W3VB8Zd5ExrNpQ50F07LskFCcl/PT1YGgRCqg6IvwjLqoES +v8qlXJVWZuXuBhqjF1na1pc8M0ZUfbXVsRfJw9CnNw6z3++C9Wg1QJerWjtSXCRw +2CHCr07AiB+nf9FxVU2QMXoU1B85R+D2KSCSJBF+fKkwVdgNwXHULtx3pci43unZ +mzJ7BtnDZ1YcFUqptlzHa6HgdmwRmB7/zSazBYtuZztX5qW++0bcF19vaoJlv7Fy +XE3Ka4FlYw== +-----END CERTIFICATE----- diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/certificate.pem b/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/certificate.pem new file mode 100644 index 0000000..f243434 --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/certificate.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDYzCCAksCFFfxHrrOeFLc3SuetPGuhqfFDBZOMA0GCSqGSIb3DQEBCwUAMG4x +CzAJBgNVBAYTAkRFMQ0wCwYDVQQIDARUZXN0MQ0wCwYDVQQHDARUZXN0MRAwDgYD +VQQKDAdUZXN0aW5nMQ0wCwYDVQQLDARUZXN0MSAwHgYDVQQDDBdjZi1qYXZhLWxv +Z2dpbmctc3VwcG9ydDAeFw0yMzEyMTQwNzA3MjJaFw0yNDEyMTMwNzA3MjJaMG4x +CzAJBgNVBAYTAkRFMQ0wCwYDVQQIDARUZXN0MQ0wCwYDVQQHDARUZXN0MRAwDgYD +VQQKDAdUZXN0aW5nMQ0wCwYDVQQLDARUZXN0MSAwHgYDVQQDDBdjZi1qYXZhLWxv +Z2dpbmctc3VwcG9ydDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK+V +L9twfgJODNYTAFgTcPK4D33DSrvxoj2KT6ddmC369xwioXTOXQtxTvzP9ypaW8D3 +rmqVQOYYj2L+2VvncEiBCXuaGb0rdaNYbOnuMdFBLbtWXlPFgVJR5js9zsxupANd +wFIYP6uFlhulyTXLBHF0tVTrhCoVdERxeF0/DUAyVid87ZVngqp+MFIZfFOKaflq +0iltypcE15nXmiIUQ3Ztf0pVgP34mRx5sE0Hz6hFObj/Yv09yq2UpuZ5gOPi86J1 +V9MimVLscsZ1oIfuPAtcAcDUc2ARaUpJHjVoHugUYKCg2pHeitAtCe9+EVdmHUTw +aqcYNPn6cQxO2c8nSFkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAKB/tE6wdl2Je +zZAyj622wEFZI73m8RjADUsa4amiox1D4pC/xUvI6N7JInvH4ty98Z25ZMv9GlBx +pwb8Arq5qR+g5HvH7W3VB8Zd5ExrNpQ50F07LskFCcl/PT1YGgRCqg6IvwjLqoES +v8qlXJVWZuXuBhqjF1na1pc8M0ZUfbXVsRfJw9CnNw6z3++C9Wg1QJerWjtSXCRw +2CHCr07AiB+nf9FxVU2QMXoU1B85R+D2KSCSJBF+fKkwVdgNwXHULtx3pci43unZ +mzJ7BtnDZ1YcFUqptlzHa6HgdmwRmB7/zSazBYtuZztX5qW++0bcF19vaoJlv7Fy +XE3Ka4FlYw== +-----END CERTIFICATE----- diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/csr.csr b/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/csr.csr new file mode 100644 index 0000000..7c9228c --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/csr.csr @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICszCCAZsCAQAwbjELMAkGA1UEBhMCREUxDTALBgNVBAgMBFRlc3QxDTALBgNV +BAcMBFRlc3QxEDAOBgNVBAoMB1Rlc3RpbmcxDTALBgNVBAsMBFRlc3QxIDAeBgNV +BAMMF2NmLWphdmEtbG9nZ2luZy1zdXBwb3J0MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAr5Uv23B+Ak4M1hMAWBNw8rgPfcNKu/GiPYpPp12YLfr3HCKh +dM5dC3FO/M/3KlpbwPeuapVA5hiPYv7ZW+dwSIEJe5oZvSt1o1hs6e4x0UEtu1Ze +U8WBUlHmOz3OzG6kA13AUhg/q4WWG6XJNcsEcXS1VOuEKhV0RHF4XT8NQDJWJ3zt +lWeCqn4wUhl8U4pp+WrSKW3KlwTXmdeaIhRDdm1/SlWA/fiZHHmwTQfPqEU5uP9i +/T3KrZSm5nmA4+LzonVX0yKZUuxyxnWgh+48C1wBwNRzYBFpSkkeNWge6BRgoKDa +kd6K0C0J734RV2YdRPBqpxg0+fpxDE7ZzydIWQIDAQABoAAwDQYJKoZIhvcNAQEL +BQADggEBAAC20jxW1rQJH/wr+cgxaImnoJNfgEIh9Qbqvbw1zNR7Qw3s8dokx8Kj +jZ36Ye9BC+i4JtV3t8ds4uzwytbFk8nTeSfys03qxIVDroIDD7EIccgVgH8N44Mc +/3chyk/qK+gRMVynlm1XLn/GSQf7ihTA8EHJDOLTJqN+Jp8O+PQ05NYrZEyKB5Wr +Q5PKe1vzpXHLndE2f0SdchIYs6lbyrCen3iBW/q23ac4FD6ppAeXqXkuCIVTovaI +SM4E5fG+OtKdOV7DtLCVCWriCmSmMBz4HeRxXdrMFeuTAL6nI+LEyURqzG/9I9iQ +qM+BE/z1Cxtie1GYZ9UTe/WCwzdN/t8= +-----END CERTIFICATE REQUEST----- diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/private.key b/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/private.key new file mode 100644 index 0000000..7e0a814 --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/private.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCvlS/bcH4CTgzW +EwBYE3DyuA99w0q78aI9ik+nXZgt+vccIqF0zl0LcU78z/cqWlvA965qlUDmGI9i +/tlb53BIgQl7mhm9K3WjWGzp7jHRQS27Vl5TxYFSUeY7Pc7MbqQDXcBSGD+rhZYb +pck1ywRxdLVU64QqFXREcXhdPw1AMlYnfO2VZ4KqfjBSGXxTimn5atIpbcqXBNeZ +15oiFEN2bX9KVYD9+JkcebBNB8+oRTm4/2L9PcqtlKbmeYDj4vOidVfTIplS7HLG +daCH7jwLXAHA1HNgEWlKSR41aB7oFGCgoNqR3orQLQnvfhFXZh1E8GqnGDT5+nEM +TtnPJ0hZAgMBAAECggEASKvxu9xqex+81lnU+Z9KT1t5Je9Pnkxbfycg4r+tPdKy +tlVrCAJlplfGfoLA5Smy8kJRUVHnI5Uku6+JXS2EXq3xs9PLNW2oaewuYAAzZE2a +1P/hWMDVTrIRHZHuZtSgU7hY4mGg8KgAwf6zMe2OMDtC1hwIfraUgcOJMubm4BuF +5gQo948q2mF0M8wYKPr3xzl9nXLaGiLXYzHKAf981qzzPxvMYnAyPwvCbSYeajE7 +sYJoxwWqAlrtSfoa8qDymMAVmRjGU/uqr7m9DlxwT79gz+rzHdvBpJEmhxwUTKzZ +MeiBaunpP/u0ilnWYaNja5GUmmrXIZghotY94/Y3RQKBgQDVOp6HWbCE/jcfCgiA +zCN0H/SmaR5mF2Hb+3WsULyl993MJbd7gpULE1XUGLkjISwapw19np4D3bWUxSY5 +9fCLTb3Yj69e7S2GW4DYHVYWLE/UkkwQ4EkSlugsRPmlKwbnER9G4N1sDtQp8l8e +mnBq8WIGe0VsjkKur2PigTFyBwKBgQDSzWvmd5Y85qW97LJBf/4IhmgShkqotwvj +beYhsJkO8coN6kW+wMK1pzt/U/JztZUijhkZDABmf8rW7Ybpc2EcVM4DLHmaowjr +O//KFf+u/buU+cvwq/seYeKlz8CPwliI6KFI6XByXZl//xlpJkmivrjoKwktWCkF +G3fKMw1anwKBgB2t1Rb90uYQBFgbq2dSArVNJV5sT0DijEp0S8K6Uie/wm2B6nIU +kO5DuLSW5F4RZfQnwGb1xwS+vWGBt3pl0x9wqLYV+dD6rlV/MwXhv3PCozHxUwke +Ts15l8NhrmXhAUr0RSg2cFt0DO/xvm+iC3e3NW+1hMpBWuK5ouuKE/nNAoGBALl8 +/hvOUImIHoEvPG78M8jGk97xAdLRNonJkz1Dynpm8XcrFHHT5cC3xVe1w1pjhjXg +uV7bu6J1gkN6wEK9Ps8SJDCQuvQBz4BFzD7C+re9FojxAK3mdtH2KdvjIbqdtQ/L +OtgQaNyJVd9V1cM7aIHmtoe8Dpgywe13jQGDyJVbAoGBAK6ys9rePjJ3uwW+CF1W +qhLopw7ZNoMyv+pOJMGVqTcnwaxZfToAA9guKrKxyusp3Zvzn/vnbTH5V0DhdRF4 +vVZq2KVbWptKIhkZkKpovsf1vQdCvLC9smgubptP80l/8HUpo0Jy4EsITJVR0BII +d1nVwQEHEp+iyFUmjkRiRmlY +-----END PRIVATE KEY----- diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/private.pem b/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/private.pem new file mode 100644 index 0000000..7e0a814 --- /dev/null +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/private.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCvlS/bcH4CTgzW +EwBYE3DyuA99w0q78aI9ik+nXZgt+vccIqF0zl0LcU78z/cqWlvA965qlUDmGI9i +/tlb53BIgQl7mhm9K3WjWGzp7jHRQS27Vl5TxYFSUeY7Pc7MbqQDXcBSGD+rhZYb +pck1ywRxdLVU64QqFXREcXhdPw1AMlYnfO2VZ4KqfjBSGXxTimn5atIpbcqXBNeZ +15oiFEN2bX9KVYD9+JkcebBNB8+oRTm4/2L9PcqtlKbmeYDj4vOidVfTIplS7HLG +daCH7jwLXAHA1HNgEWlKSR41aB7oFGCgoNqR3orQLQnvfhFXZh1E8GqnGDT5+nEM +TtnPJ0hZAgMBAAECggEASKvxu9xqex+81lnU+Z9KT1t5Je9Pnkxbfycg4r+tPdKy +tlVrCAJlplfGfoLA5Smy8kJRUVHnI5Uku6+JXS2EXq3xs9PLNW2oaewuYAAzZE2a +1P/hWMDVTrIRHZHuZtSgU7hY4mGg8KgAwf6zMe2OMDtC1hwIfraUgcOJMubm4BuF +5gQo948q2mF0M8wYKPr3xzl9nXLaGiLXYzHKAf981qzzPxvMYnAyPwvCbSYeajE7 +sYJoxwWqAlrtSfoa8qDymMAVmRjGU/uqr7m9DlxwT79gz+rzHdvBpJEmhxwUTKzZ +MeiBaunpP/u0ilnWYaNja5GUmmrXIZghotY94/Y3RQKBgQDVOp6HWbCE/jcfCgiA +zCN0H/SmaR5mF2Hb+3WsULyl993MJbd7gpULE1XUGLkjISwapw19np4D3bWUxSY5 +9fCLTb3Yj69e7S2GW4DYHVYWLE/UkkwQ4EkSlugsRPmlKwbnER9G4N1sDtQp8l8e +mnBq8WIGe0VsjkKur2PigTFyBwKBgQDSzWvmd5Y85qW97LJBf/4IhmgShkqotwvj +beYhsJkO8coN6kW+wMK1pzt/U/JztZUijhkZDABmf8rW7Ybpc2EcVM4DLHmaowjr +O//KFf+u/buU+cvwq/seYeKlz8CPwliI6KFI6XByXZl//xlpJkmivrjoKwktWCkF +G3fKMw1anwKBgB2t1Rb90uYQBFgbq2dSArVNJV5sT0DijEp0S8K6Uie/wm2B6nIU +kO5DuLSW5F4RZfQnwGb1xwS+vWGBt3pl0x9wqLYV+dD6rlV/MwXhv3PCozHxUwke +Ts15l8NhrmXhAUr0RSg2cFt0DO/xvm+iC3e3NW+1hMpBWuK5ouuKE/nNAoGBALl8 +/hvOUImIHoEvPG78M8jGk97xAdLRNonJkz1Dynpm8XcrFHHT5cC3xVe1w1pjhjXg +uV7bu6J1gkN6wEK9Ps8SJDCQuvQBz4BFzD7C+re9FojxAK3mdtH2KdvjIbqdtQ/L +OtgQaNyJVd9V1cM7aIHmtoe8Dpgywe13jQGDyJVbAoGBAK6ys9rePjJ3uwW+CF1W +qhLopw7ZNoMyv+pOJMGVqTcnwaxZfToAA9guKrKxyusp3Zvzn/vnbTH5V0DhdRF4 +vVZq2KVbWptKIhkZkKpovsf1vQdCvLC9smgubptP80l/8HUpo0Jy4EsITJVR0BII +d1nVwQEHEp+iyFUmjkRiRmlY +-----END PRIVATE KEY----- From dac86a05814660e73d5cddef6a729e38440d7bb0 Mon Sep 17 00:00:00 2001 From: Karsten Schnitter Date: Fri, 29 Dec 2023 08:28:08 +0100 Subject: [PATCH 3/6] Improve CF resource attributes Fixes source id and adds process attributes. Signed-off-by: Karsten Schnitter --- .../ext/attributes/CloudFoundryResourceCustomizer.java | 4 +++- .../attributes/CloudFoundryResourceCustomizerTest.java | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/attributes/CloudFoundryResourceCustomizer.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/attributes/CloudFoundryResourceCustomizer.java index fee1487..3a2795e 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/attributes/CloudFoundryResourceCustomizer.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/attributes/CloudFoundryResourceCustomizer.java @@ -34,7 +34,7 @@ public Resource apply(Resource resource, ConfigProperties configProperties) { CfApplication cfApp = cfEnv.getApp(); ResourceBuilder rb = Resource.builder(); rb.put("service.name", cfApp.getApplicationName()); - rb.put("sap.cf.source_id", getString(cfApp, "source_id")); + rb.put("sap.cf.source_id", cfApp.getApplicationId()); rb.put("sap.cf.instance_id", cfApp.getInstanceIndex()); rb.put("sap.cf.app_id", cfApp.getApplicationId()); rb.put("sap.cf.app_name", cfApp.getApplicationName()); @@ -42,6 +42,8 @@ public Resource apply(Resource resource, ConfigProperties configProperties) { rb.put("sap.cf.space_name", cfApp.getSpaceName()); rb.put("sap.cf.org_id", getString(cfApp, "organization_id")); rb.put("sap.cf.org_name", getString(cfApp, "organization_name")); + rb.put("sap.cf.process.id", getString(cfApp, "process_id")); + rb.put("sap.cf.process.type", getString(cfApp, "process_type")); return rb.build(); } diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/attributes/CloudFoundryResourceCustomizerTest.java b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/attributes/CloudFoundryResourceCustomizerTest.java index 7e86ab2..0894640 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/attributes/CloudFoundryResourceCustomizerTest.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/attributes/CloudFoundryResourceCustomizerTest.java @@ -45,8 +45,10 @@ public void fillsResourceFromVcapApplication() { applicationData.put("application_name", "test-application"); applicationData.put("space_name", "test-space"); applicationData.put("organization_name", "test-org"); - applicationData.put("source_id", "test-source"); + applicationData.put("application_id", "test-app-id"); applicationData.put("instance_index", 42); + applicationData.put("process_id", "test-process-id"); + applicationData.put("process_type", "test-process-type"); when(cfEnv.getApp()).thenReturn(new CfApplication(applicationData)); CloudFoundryResourceCustomizer customizer = new CloudFoundryResourceCustomizer(cfEnv); @@ -55,7 +57,9 @@ public void fillsResourceFromVcapApplication() { assertEquals("test-application", resource.getAttribute(AttributeKey.stringKey("sap.cf.app_name"))); assertEquals("test-space", resource.getAttribute(AttributeKey.stringKey("sap.cf.space_name"))); assertEquals("test-org", resource.getAttribute(AttributeKey.stringKey("sap.cf.org_name"))); - assertEquals("test-source", resource.getAttribute(AttributeKey.stringKey("sap.cf.source_id"))); + assertEquals("test-app-id", resource.getAttribute(AttributeKey.stringKey("sap.cf.source_id"))); assertEquals(42, resource.getAttribute(AttributeKey.longKey("sap.cf.instance_id")).longValue()); + assertEquals("test-process-id", resource.getAttribute(AttributeKey.stringKey("sap.cf.process.id"))); + assertEquals("test-process-type", resource.getAttribute(AttributeKey.stringKey("sap.cf.process.type"))); } } \ No newline at end of file From 9ded83d19ac3196cea1cb78244d9e48924728691 Mon Sep 17 00:00:00 2001 From: Karsten Schnitter Date: Tue, 9 Jan 2024 14:55:02 +0100 Subject: [PATCH 4/6] Refactor Service Binding Detection Use the same service binding scanning in old and new exporter configuration. Signed-off-by: Karsten Schnitter --- ...CloudLoggingBindingPropertiesSupplier.java | 20 ++++++++++--------- .../CloudLoggingServicesProvider.java | 4 ++-- .../CloudLoggingLogsExporterProvider.java | 1 + .../CloudLoggingMetricsExporterProvider.java | 1 + .../CloudLoggingSpanExporterProvider.java | 1 + .../CloudLoggingServicesProviderTest.java | 3 ++- 6 files changed, 18 insertions(+), 12 deletions(-) rename cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/{exporter => binding}/CloudLoggingServicesProvider.java (93%) rename cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/{exporter => binding}/CloudLoggingServicesProviderTest.java (95%) diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingBindingPropertiesSupplier.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingBindingPropertiesSupplier.java index 7a044e6..98bf9ce 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingBindingPropertiesSupplier.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingBindingPropertiesSupplier.java @@ -1,5 +1,7 @@ package com.sap.hcf.cf.logging.opentelemetry.agent.ext.binding; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; import io.pivotal.cfenv.core.CfEnv; import io.pivotal.cfenv.core.CfService; @@ -21,13 +23,16 @@ public class CloudLoggingBindingPropertiesSupplier implements Supplier defaults = new HashMap<>(); + defaults.put("com.sap.otel.extension.cloud-logging.label", "cloud-logging"); + defaults.put("com.sap.otel.extension.cloud-logging.tag", "Cloud Logging"); + defaults.put("otel.javaagent.extension.sap.cf.binding.user-provided.label", "user-provided"); + ConfigProperties configProperties = DefaultConfigProperties.create(defaults); + this.cloudLoggingServicesProvider = new CloudLoggingServicesProvider(configProperties, cfEnv); } private static boolean isBlank(String text) { @@ -54,10 +59,7 @@ private static File writeFile(String prefix, String suffix, String content) thro */ @Override public Map get() { - Stream userProvided = cfEnv.findServicesByLabel(USER_PROVIDED_LABEL).stream(); - Stream managed = cfEnv.findServicesByLabel(CLOUD_LOGGING_LABEL).stream(); - return Stream.concat(userProvided, managed) - .filter(svc -> svc.existsByTagIgnoreCase(CLOUD_LOGGING_TAG)) + return cloudLoggingServicesProvider.get() .findFirst() .map(this::createEndpointConfiguration).orElseGet(Collections::emptyMap); } diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingServicesProvider.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingServicesProvider.java similarity index 93% rename from cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingServicesProvider.java rename to cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingServicesProvider.java index 1e35c2b..0ef8a0c 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingServicesProvider.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingServicesProvider.java @@ -1,4 +1,4 @@ -package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.binding; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.pivotal.cfenv.core.CfEnv; @@ -9,7 +9,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -class CloudLoggingServicesProvider implements Supplier> { +public class CloudLoggingServicesProvider implements Supplier> { private static final String DEFAULT_USER_PROVIDED_LABEL = "user-provided"; private static final String DEFAULT_CLOUD_LOGGING_LABEL = "cloud-logging"; diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingLogsExporterProvider.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingLogsExporterProvider.java index 2d86135..72971e6 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingLogsExporterProvider.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingLogsExporterProvider.java @@ -1,5 +1,6 @@ package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; +import com.sap.hcf.cf.logging.opentelemetry.agent.ext.binding.CloudLoggingServicesProvider; import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingMetricsExporterProvider.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingMetricsExporterProvider.java index d9e0dd1..b5ec3d4 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingMetricsExporterProvider.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingMetricsExporterProvider.java @@ -1,5 +1,6 @@ package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; +import com.sap.hcf.cf.logging.opentelemetry.agent.ext.binding.CloudLoggingServicesProvider; import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter; import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingSpanExporterProvider.java b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingSpanExporterProvider.java index c3fa87c..6bbcd0b 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingSpanExporterProvider.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/main/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingSpanExporterProvider.java @@ -1,5 +1,6 @@ package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; +import com.sap.hcf.cf.logging.opentelemetry.agent.ext.binding.CloudLoggingServicesProvider; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingServicesProviderTest.java b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingServicesProviderTest.java similarity index 95% rename from cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingServicesProviderTest.java rename to cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingServicesProviderTest.java index ddfa313..701dc94 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/exporter/CloudLoggingServicesProviderTest.java +++ b/cf-java-logging-support-opentelemetry-agent-extension/src/test/java/com/sap/hcf/cf/logging/opentelemetry/agent/ext/binding/CloudLoggingServicesProviderTest.java @@ -1,5 +1,6 @@ -package com.sap.hcf.cf.logging.opentelemetry.agent.ext.exporter; +package com.sap.hcf.cf.logging.opentelemetry.agent.ext.binding; +import com.sap.hcf.cf.logging.opentelemetry.agent.ext.binding.CloudLoggingServicesProvider; import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; import io.pivotal.cfenv.core.CfEnv; import io.pivotal.cfenv.core.CfService; From e99fb8abbf3755a1ad7ca72dbde23a442c04f0e9 Mon Sep 17 00:00:00 2001 From: Karsten Schnitter Date: Tue, 9 Jan 2024 15:10:17 +0100 Subject: [PATCH 5/6] Adjust Documentation for Cloud-Logging Add references to the `cloud-logging`exporter to the documentation. Describe the new config properties to control the extension. Signed-off-by: Karsten Schnitter --- .../README.md | 92 ++++++++++++++++--- .../manifest-otel-javaagent.yml | 2 +- 2 files changed, 78 insertions(+), 16 deletions(-) diff --git a/cf-java-logging-support-opentelemetry-agent-extension/README.md b/cf-java-logging-support-opentelemetry-agent-extension/README.md index f14cc20..8329794 100644 --- a/cf-java-logging-support-opentelemetry-agent-extension/README.md +++ b/cf-java-logging-support-opentelemetry-agent-extension/README.md @@ -1,14 +1,15 @@ # OpenTelemetry Java Agent Extension for SAP Cloud Logging This module provides an extension for the [OpenTelemetry Java Agent](https://opentelemetry.io/docs/instrumentation/java/automatic/). -The extension scans the service bindings of an application for SAP Cloud Logging. +The extension scans the service bindings of an application for [SAP Cloud Logging](https://discovery-center.cloud.sap/serviceCatalog/cloud-logging). If such a binding is found, the OpenTelemetry Java Agent is configured to ship observability data to that service. Thus, this extension provides a convenient auto-instrumentation for Java applications running on SAP BTP. -The extension provides two main features: +The extension provides the following main features: -* auto-configuration of the OpenTelemetry connection to SAP Cloud Logging -* adding resource attributes to describe the CF application +* additional exporters for logs, metrics and traces for [SAP Cloud Logging](https://discovery-center.cloud.sap/serviceCatalog/cloud-logging) +* auto-configuration of the generic OpenTelemetry connection to [SAP Cloud Logging](https://discovery-center.cloud.sap/serviceCatalog/cloud-logging) +* adding resource attributes describing the CF application See the section on [configuration](#configuration) for further details. @@ -18,7 +19,7 @@ Any Java application can be instrumented with the OpenTelemetry Java Agent and t ```sh java -javaagent:/path/to/opentelemetry-javaagent-.jar \ - -Dotel.javaagent-extensions=/path/to/cf-java-logging-support-opentelemetry-agent-extension-.jar \ + -Dotel.javaagent-extensions=/path/to/cf-java-logging-support-opentelemetry-agent-extension-.jar \ # your Java application command ``` @@ -37,11 +38,45 @@ java -javaagent:BOOT-INF/lib/opentelemetry-javaagent-.jar \ See the [example manifest](../sample-spring-boot/manifest-otel-javaagent.yml), how this translates into a deployment description. -For the instrumentation to send observability data to SAP Cloud Logging, the application needs to be bound to a corresponding service instance. -The service instance can be either managed or [user-provided](#using-user-provided-service-instances). +Once the agent is attached to the JVM with the ectension in place, there are two ways, which can be used to send data to [SAP Cloud Logging](https://discovery-center.cloud.sap/serviceCatalog/cloud-logging): + +1. Use the `cloud-logging` exporters explicitly as provided by the extension. +This can be achieved via system properties or environment variables: +```sh +-Dotel.logs.exporter=cloud-logging \ +-Dotel.metrics.exporter=cloud-logging \ +-Dotel.traces.exporter=cloud-logging + +#or + +export OTEL_LOGS_EXPORTER=cloud-logging +export OTEL_METRICS_EXPORTER=cloud-logging +export OTEL_TRACES_EXPORTER=cloud-logging +java #... +``` + +2. Use the default `otlp` exporter with the provided default configuration from the extension: + +```sh +-Dotel.logs.exporter=otlp \ +-Dotel.metrics.exporter=otlp # default value \ +-Dotel.traces.exporter=otlp # default value + +#or -Note, that the OpenTelemetry Java Agent currently only sends traces and metrics by default. -To enable logs, the additional property `-Dotel.logs.exporter=otlp` is required. +export OTEL_LOGS_EXPORTER=otlp +export OTEL_METRICS_EXPORTER=otlp # default value +export OTEL_TRACES_EXPORTER=otlp # default value +java #... +``` + +Note, that the OpenTelemetry Java Agent currently sends traces and metrics by default using the `otlp` exporter. +That means, without any configuration the agent with the extension will forward metrics and traces to [SAP Cloud Logging](https://discovery-center.cloud.sap/serviceCatalog/cloud-logging). +See TODO for the difference between `cloud-logging` and `otlp` exporters. +The benefit of the `cloud-logging` exporter is, that it can be combined with a different configuration of the `otlp` exporter. + +For the instrumentation to send observability data to [SAP Cloud Logging](https://discovery-center.cloud.sap/serviceCatalog/cloud-logging), the application needs to be bound to a corresponding service instance. +The service instance can be either managed or [user-provided](#using-user-provided-service-instances). ## Configuration @@ -49,15 +84,30 @@ The OpenTelemetry Java Agent supports a wide variety of [configuration options]( As the extension provides configuration via SPI, all its configuration takes lower precedence than other configuration options for OpenTelemetry. Users can easily overwrite any setting using environment variables or system properties. +### Using the Extension + +The extension needs to be started with the OpenTelemetry Java Agent as outlined in the [Quick Start Guide](#quickstart-guide). +You need to enable shipping data either by using the `cloud-logging` exporters or relying on the `otlp` exporters for each signal type. +Multiple different exporters can be configured with comma separation. +Using the custom `cloud-logging` exporter will enable you, to use the default `otlp` exporter for different services. +The extension will configure a default endpoint and credentials for the `otlp` endpoints, so no further configuration is required. + +Note, that the `cloud-logging` exporter is just a facade for the `otlp` exporter to allow configuration of multiple data sinks. +There is no custom network client provided by this extension. + ### Configuring the Extension The extension itself can be configured by specifying the following system properties: | Property | Default Value | Comment | |----------|---------------|---------| -| `com.sap.otel.extension.cloud-logging.label` | `cloud-logging` | The label of the managed service binding to bind to. | -| `com.sap.otel.extension.cloud-logging.tag` | `Cloud Logging` | The tag of any service binding (managed or user-provided) to bind to. | -| `otel.javaagent.extension.sap.cf.resource.enabled` or `env(OTEL_JAVAAGENT_EXTENSION_SAP_CF_RESOURCE_ENABLED)` | `true` | Whether to add CF resource attributes to all events. | +| `otel.javaagent.extension.sap.cf.binding.cloud-logging.label` or `com.sap.otel.extension.cloud-logging.label` | `cloud-logging` | The label of the managed service binding to bind to. | +| `otel.javaagent.extension.sap.cf.binding.cloud-logging.tag` or `com.sap.otel.extension.cloud-logging.tag` | `Cloud Logging` | The tag of any service binding (managed or user-provided) to bind to. | +| `otel.javaagent.extension.sap.cf.binding.user-provided.label` | `user-provided` | The label of a user-provided service binding to bind to. Note, this label is defined by the Cloud Foundry instance. | +| `otel.javaagent.extension.sap.cf.resource.enabled` | `true` | Whether to add CF resource attributes to all events. | + +> The `otel.javaagent.extension.sap.*` properties are preferred over the `com.sap.otel.extension.*` properties, which are kept for compatibility. +Each `otel.javaagent.extension.sap.*` property can also be provided as environment variable `OTEL_JAVAAGENT_EXTENSION_SAP_*`. The extension will scan the environment variable `VCAP_SERVICES` for CF service bindings. User-provided bindings will take precedence over managed bindings of the configured label ("cloud-logging" by default). @@ -90,7 +140,7 @@ The [OpenTelemetry Java Instrumentation project](https://github.com/open-telemet ## Using User-Provided Service Instances -The extension provides support not only for managed service instance of SAP Cloud Logging but also for user-provided service instances. +The extension provides support not only for managed service instance of [SAP Cloud Logging](https://discovery-center.cloud.sap/serviceCatalog/cloud-logging) but also for user-provided service instances. This helps to fine-tune the configuration, e.g. leave out or reconfigure the syslog drain. Furthermore, this helps on sharing service instances across CF orgs or landscapes. @@ -103,7 +153,7 @@ The extension requires four fields in the user-provided service credentials and | `ingest-otlp-cert`| The mTLS client certificate in PEM format matching the client key. Line breaks as `\n`. | | `server-ca` | The trusted mTLS server certificate in PEM format. Line breaks as `\n`. | -If you have a SAP Cloud Logging service key, you can generate the required JSON file with jq: +If you have a [SAP Cloud Logging](https://discovery-center.cloud.sap/serviceCatalog/cloud-logging) service key, you can generate the required JSON file with jq: ```bash cf service-key cls test \ @@ -119,5 +169,17 @@ Using this file, you can create the required user-provided service: ``` Note, that you can easily feed arbitrary credentials to the extension. -It does not need to be SAP Cloud Logging. +It does not need to be [SAP Cloud Logging](https://discovery-center.cloud.sap/serviceCatalog/cloud-logging). You can even change the tag using the configuration parameters of the extension. + +## Implementation Differences between Cloud-Logging and OTLP Exporter + +The `cloud-logging` exporter provided by this extension is a facade for the `OtlpGrpcExporter` provided by the OpenTelemetry Java Agent, just like the `otlp` exporter. +The difference is just during the bootstrapping phase. +The main differences are: + +* The `cloud-logging` exporter will send data to all found bindings to SAP Cloud Logging. +The auto-instrumentation of the `otlp` exporter will just configure the first binding it finds priotizing user-provided services. +* The `otlp` configuration will write the required certificates and keys to temporary files, which are deleted when the JVM is shut down. The `cloud-logging` exporter will keep the secrets in memory. +* Since the `otlp` exporter is the default for traces and metrics, just attaching the extension and binding to Cloud Logging will result in metrics and traces being forwarded. +The `cloud-logging` exporter needs to be configured explictly as does the `otlp` exporter for logs. diff --git a/sample-spring-boot/manifest-otel-javaagent.yml b/sample-spring-boot/manifest-otel-javaagent.yml index 434f2e1..f6a3500 100644 --- a/sample-spring-boot/manifest-otel-javaagent.yml +++ b/sample-spring-boot/manifest-otel-javaagent.yml @@ -15,7 +15,7 @@ applications: LOG_REFERER: false JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jre.SAPMachineJRE']" JBP_CONFIG_SAP_MACHINE_JRE: '{ use_offline_repository: false, version: 17.+ }' - JBP_CONFIG_JAVA_OPTS: '[from_environment: false, java_opts: ''-javaagent:BOOT-INF/lib/opentelemetry-javaagent-1.31.0.jar -Dotel.javaagent.extensions=BOOT-INF/lib/cf-java-logging-support-opentelemetry-agent-extension-3.8.0.jar -Dotel.logs.exporter=otlp -Dotel.instrumentation.logback-appender.experimental.capture-mdc-attributes=* -Dotel.instrumentation.logback-appender.experimental.capture-key-value-pair-attributes=true -Dotel.instrumentation.logback-appender.experimental.capture-code-attributes=true -Dotel.instrumentation.logback-appender.experimental-log-attributes=true -Dotel.experimental.resource.disabled-keys=process.command_line,process.command_args,process.executable.path'']' + JBP_CONFIG_JAVA_OPTS: '[from_environment: false, java_opts: ''-javaagent:BOOT-INF/lib/opentelemetry-javaagent-1.31.0.jar -Dotel.javaagent.extensions=BOOT-INF/lib/cf-java-logging-support-opentelemetry-agent-extension-3.8.0.jar -Dotel.logs.exporter=cloud-logging,otlp -Dotel.instrumentation.logback-appender.experimental.capture-mdc-attributes=* -Dotel.instrumentation.logback-appender.experimental.capture-key-value-pair-attributes=true -Dotel.instrumentation.logback-appender.experimental.capture-code-attributes=true -Dotel.instrumentation.logback-appender.experimental-log-attributes=true -Dotel.experimental.resource.disabled-keys=process.command_line,process.command_args,process.executable.path'']' services: - cls From edf8762945214fc5a9cdcef75a3883b14910e8c1 Mon Sep 17 00:00:00 2001 From: Karsten Schnitter Date: Fri, 12 Jan 2024 15:34:32 +0100 Subject: [PATCH 6/6] Remove Security Test Artifacts Delete unnecessary files from key and certificate creation. Signed-off-by: Karsten Schnitter --- .../src/test/resources/certificate.crt | 21 -------------- .../src/test/resources/csr.csr | 17 ----------- .../src/test/resources/private.key | 28 ------------------- 3 files changed, 66 deletions(-) delete mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/certificate.crt delete mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/csr.csr delete mode 100644 cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/private.key diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/certificate.crt b/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/certificate.crt deleted file mode 100644 index f243434..0000000 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/certificate.crt +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDYzCCAksCFFfxHrrOeFLc3SuetPGuhqfFDBZOMA0GCSqGSIb3DQEBCwUAMG4x -CzAJBgNVBAYTAkRFMQ0wCwYDVQQIDARUZXN0MQ0wCwYDVQQHDARUZXN0MRAwDgYD -VQQKDAdUZXN0aW5nMQ0wCwYDVQQLDARUZXN0MSAwHgYDVQQDDBdjZi1qYXZhLWxv -Z2dpbmctc3VwcG9ydDAeFw0yMzEyMTQwNzA3MjJaFw0yNDEyMTMwNzA3MjJaMG4x -CzAJBgNVBAYTAkRFMQ0wCwYDVQQIDARUZXN0MQ0wCwYDVQQHDARUZXN0MRAwDgYD -VQQKDAdUZXN0aW5nMQ0wCwYDVQQLDARUZXN0MSAwHgYDVQQDDBdjZi1qYXZhLWxv -Z2dpbmctc3VwcG9ydDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK+V -L9twfgJODNYTAFgTcPK4D33DSrvxoj2KT6ddmC369xwioXTOXQtxTvzP9ypaW8D3 -rmqVQOYYj2L+2VvncEiBCXuaGb0rdaNYbOnuMdFBLbtWXlPFgVJR5js9zsxupANd -wFIYP6uFlhulyTXLBHF0tVTrhCoVdERxeF0/DUAyVid87ZVngqp+MFIZfFOKaflq -0iltypcE15nXmiIUQ3Ztf0pVgP34mRx5sE0Hz6hFObj/Yv09yq2UpuZ5gOPi86J1 -V9MimVLscsZ1oIfuPAtcAcDUc2ARaUpJHjVoHugUYKCg2pHeitAtCe9+EVdmHUTw -aqcYNPn6cQxO2c8nSFkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAKB/tE6wdl2Je -zZAyj622wEFZI73m8RjADUsa4amiox1D4pC/xUvI6N7JInvH4ty98Z25ZMv9GlBx -pwb8Arq5qR+g5HvH7W3VB8Zd5ExrNpQ50F07LskFCcl/PT1YGgRCqg6IvwjLqoES -v8qlXJVWZuXuBhqjF1na1pc8M0ZUfbXVsRfJw9CnNw6z3++C9Wg1QJerWjtSXCRw -2CHCr07AiB+nf9FxVU2QMXoU1B85R+D2KSCSJBF+fKkwVdgNwXHULtx3pci43unZ -mzJ7BtnDZ1YcFUqptlzHa6HgdmwRmB7/zSazBYtuZztX5qW++0bcF19vaoJlv7Fy -XE3Ka4FlYw== ------END CERTIFICATE----- diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/csr.csr b/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/csr.csr deleted file mode 100644 index 7c9228c..0000000 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/csr.csr +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIICszCCAZsCAQAwbjELMAkGA1UEBhMCREUxDTALBgNVBAgMBFRlc3QxDTALBgNV -BAcMBFRlc3QxEDAOBgNVBAoMB1Rlc3RpbmcxDTALBgNVBAsMBFRlc3QxIDAeBgNV -BAMMF2NmLWphdmEtbG9nZ2luZy1zdXBwb3J0MIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEAr5Uv23B+Ak4M1hMAWBNw8rgPfcNKu/GiPYpPp12YLfr3HCKh -dM5dC3FO/M/3KlpbwPeuapVA5hiPYv7ZW+dwSIEJe5oZvSt1o1hs6e4x0UEtu1Ze -U8WBUlHmOz3OzG6kA13AUhg/q4WWG6XJNcsEcXS1VOuEKhV0RHF4XT8NQDJWJ3zt -lWeCqn4wUhl8U4pp+WrSKW3KlwTXmdeaIhRDdm1/SlWA/fiZHHmwTQfPqEU5uP9i -/T3KrZSm5nmA4+LzonVX0yKZUuxyxnWgh+48C1wBwNRzYBFpSkkeNWge6BRgoKDa -kd6K0C0J734RV2YdRPBqpxg0+fpxDE7ZzydIWQIDAQABoAAwDQYJKoZIhvcNAQEL -BQADggEBAAC20jxW1rQJH/wr+cgxaImnoJNfgEIh9Qbqvbw1zNR7Qw3s8dokx8Kj -jZ36Ye9BC+i4JtV3t8ds4uzwytbFk8nTeSfys03qxIVDroIDD7EIccgVgH8N44Mc -/3chyk/qK+gRMVynlm1XLn/GSQf7ihTA8EHJDOLTJqN+Jp8O+PQ05NYrZEyKB5Wr -Q5PKe1vzpXHLndE2f0SdchIYs6lbyrCen3iBW/q23ac4FD6ppAeXqXkuCIVTovaI -SM4E5fG+OtKdOV7DtLCVCWriCmSmMBz4HeRxXdrMFeuTAL6nI+LEyURqzG/9I9iQ -qM+BE/z1Cxtie1GYZ9UTe/WCwzdN/t8= ------END CERTIFICATE REQUEST----- diff --git a/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/private.key b/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/private.key deleted file mode 100644 index 7e0a814..0000000 --- a/cf-java-logging-support-opentelemetry-agent-extension/src/test/resources/private.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCvlS/bcH4CTgzW -EwBYE3DyuA99w0q78aI9ik+nXZgt+vccIqF0zl0LcU78z/cqWlvA965qlUDmGI9i -/tlb53BIgQl7mhm9K3WjWGzp7jHRQS27Vl5TxYFSUeY7Pc7MbqQDXcBSGD+rhZYb -pck1ywRxdLVU64QqFXREcXhdPw1AMlYnfO2VZ4KqfjBSGXxTimn5atIpbcqXBNeZ -15oiFEN2bX9KVYD9+JkcebBNB8+oRTm4/2L9PcqtlKbmeYDj4vOidVfTIplS7HLG -daCH7jwLXAHA1HNgEWlKSR41aB7oFGCgoNqR3orQLQnvfhFXZh1E8GqnGDT5+nEM -TtnPJ0hZAgMBAAECggEASKvxu9xqex+81lnU+Z9KT1t5Je9Pnkxbfycg4r+tPdKy -tlVrCAJlplfGfoLA5Smy8kJRUVHnI5Uku6+JXS2EXq3xs9PLNW2oaewuYAAzZE2a -1P/hWMDVTrIRHZHuZtSgU7hY4mGg8KgAwf6zMe2OMDtC1hwIfraUgcOJMubm4BuF -5gQo948q2mF0M8wYKPr3xzl9nXLaGiLXYzHKAf981qzzPxvMYnAyPwvCbSYeajE7 -sYJoxwWqAlrtSfoa8qDymMAVmRjGU/uqr7m9DlxwT79gz+rzHdvBpJEmhxwUTKzZ -MeiBaunpP/u0ilnWYaNja5GUmmrXIZghotY94/Y3RQKBgQDVOp6HWbCE/jcfCgiA -zCN0H/SmaR5mF2Hb+3WsULyl993MJbd7gpULE1XUGLkjISwapw19np4D3bWUxSY5 -9fCLTb3Yj69e7S2GW4DYHVYWLE/UkkwQ4EkSlugsRPmlKwbnER9G4N1sDtQp8l8e -mnBq8WIGe0VsjkKur2PigTFyBwKBgQDSzWvmd5Y85qW97LJBf/4IhmgShkqotwvj -beYhsJkO8coN6kW+wMK1pzt/U/JztZUijhkZDABmf8rW7Ybpc2EcVM4DLHmaowjr -O//KFf+u/buU+cvwq/seYeKlz8CPwliI6KFI6XByXZl//xlpJkmivrjoKwktWCkF -G3fKMw1anwKBgB2t1Rb90uYQBFgbq2dSArVNJV5sT0DijEp0S8K6Uie/wm2B6nIU -kO5DuLSW5F4RZfQnwGb1xwS+vWGBt3pl0x9wqLYV+dD6rlV/MwXhv3PCozHxUwke -Ts15l8NhrmXhAUr0RSg2cFt0DO/xvm+iC3e3NW+1hMpBWuK5ouuKE/nNAoGBALl8 -/hvOUImIHoEvPG78M8jGk97xAdLRNonJkz1Dynpm8XcrFHHT5cC3xVe1w1pjhjXg -uV7bu6J1gkN6wEK9Ps8SJDCQuvQBz4BFzD7C+re9FojxAK3mdtH2KdvjIbqdtQ/L -OtgQaNyJVd9V1cM7aIHmtoe8Dpgywe13jQGDyJVbAoGBAK6ys9rePjJ3uwW+CF1W -qhLopw7ZNoMyv+pOJMGVqTcnwaxZfToAA9guKrKxyusp3Zvzn/vnbTH5V0DhdRF4 -vVZq2KVbWptKIhkZkKpovsf1vQdCvLC9smgubptP80l/8HUpo0Jy4EsITJVR0BII -d1nVwQEHEp+iyFUmjkRiRmlY ------END PRIVATE KEY-----