2 * ========================LICENSE_START=================================
4 * ======================================================================
5 * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved.
6 * ======================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ========================LICENSE_END===================================
20 package org.onap.ccsdk.oran.a1policymanagementservice.configuration;
22 import io.micrometer.observation.ObservationPredicate;
23 import io.micrometer.observation.ObservationRegistry;
24 import io.opentelemetry.api.OpenTelemetry;
25 import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
26 import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
27 import io.opentelemetry.instrumentation.spring.webflux.v5_3.SpringWebfluxTelemetry;
28 import io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSampler;
29 import io.opentelemetry.sdk.trace.samplers.Sampler;
31 import reactor.core.publisher.Hooks;
33 import java.time.Duration;
35 import javax.annotation.PostConstruct;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39 import org.springframework.beans.factory.annotation.Value;
40 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
41 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
42 import org.springframework.context.annotation.Bean;
43 import org.springframework.context.annotation.ComponentScan;
44 import org.springframework.context.annotation.Configuration;
45 import org.springframework.http.server.observation.ServerRequestObservationContext;
46 import org.springframework.boot.actuate.autoconfigure.observation.ObservationRegistryCustomizer;
47 import org.springframework.util.AntPathMatcher;
48 import org.springframework.util.PathMatcher;
51 @ComponentScan(basePackages = {"org.onap.ccsdk.oran.a1policymanagementservice"})
52 public class OtelConfig {
53 private static final Logger logger = LoggerFactory.getLogger(OtelConfig.class);
55 public static final int JAEGER_REMOTE_SAMPLER_POLLING_INTERVAL_IN_SECOND = 30;
57 @Value("${spring.application.name}")
58 private String serviceId;
60 @Value("${management.tracing.exporter.endpoint}")
61 private String tracingExporterEndpointUrl;
63 @Value("${management.tracing.sampler.jaeger-remote.endpoint}")
64 private String jaegerRemoteSamplerUrl;
66 @Value("${management.tracing.exporter.protocol}")
67 private String tracingProtocol;
70 @Value("${management.tracing.enabled}")
71 private boolean tracingEnabled;
74 public void checkTracingConfig() {
75 logger.info("Application Yaml Tracing Enabled: " + tracingEnabled);
79 @ConditionalOnProperty(prefix = "management.tracing", name = "enabled", havingValue = "true", matchIfMissing = false)
80 @ConditionalOnExpression("'grpc'.equals('${management.tracing.exporter.protocol}')")
81 public OtlpGrpcSpanExporter otlpExporterGrpc() {
82 return OtlpGrpcSpanExporter.builder().setEndpoint(tracingExporterEndpointUrl).build();
86 @ConditionalOnProperty(prefix = "management.tracing", name = "enabled", havingValue = "true", matchIfMissing = false)
87 @ConditionalOnExpression("'http'.equals('${management.tracing.exporter.protocol}')")
88 public OtlpHttpSpanExporter otlpExporterHttp() {
89 return OtlpHttpSpanExporter.builder().setEndpoint(tracingExporterEndpointUrl).build();
93 @ConditionalOnProperty(prefix = "management.tracing", name = "enabled", havingValue = "true", matchIfMissing = false)
94 public JaegerRemoteSampler jaegerRemoteSampler() {
95 return JaegerRemoteSampler.builder().setEndpoint(jaegerRemoteSamplerUrl)
96 .setPollingInterval(Duration.ofSeconds(JAEGER_REMOTE_SAMPLER_POLLING_INTERVAL_IN_SECOND))
97 .setInitialSampler(Sampler.alwaysOff()).setServiceName(serviceId).build();
101 @ConditionalOnProperty(prefix = "management.tracing", name = "enabled", havingValue = "true", matchIfMissing = false)
102 public SpringWebfluxTelemetry webfluxTelemetry (OpenTelemetry openTelemetry) {
103 //enables automatic context propagation to ThreadLocals used by FLUX and MONO operators
104 Hooks.enableAutomaticContextPropagation();
105 return SpringWebfluxTelemetry.builder(openTelemetry).build();
109 @ConditionalOnProperty(prefix = "management.tracing", name = "enabled", havingValue = "true", matchIfMissing = false)
110 ObservationRegistryCustomizer<ObservationRegistry> skipActuatorEndpointsFromObservation() {
111 PathMatcher pathMatcher = new AntPathMatcher("/");
113 registry.observationConfig().observationPredicate(observationPredicate(pathMatcher));
116 static ObservationPredicate observationPredicate(PathMatcher pathMatcher) {
117 return (name, context) -> {
118 if (context instanceof ServerRequestObservationContext observationContext) {
119 return !pathMatcher.match("/actuator/**", observationContext.getCarrier().getRequestURI());