Skip to content

Commit da9417c

Browse files
committed
[pinpoint-apm#10776] Add open telemetry metric receiver to metric collector
1 parent e72bbed commit da9417c

37 files changed

+2300
-3
lines changed

agent-module/agent/src/main/resources/profiles/local/pinpoint.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1435,5 +1435,5 @@ profiler.resilience4j.mark.error.circuit-breaker=false
14351435
profiler.micrometer.otlp.enabled=true
14361436
profiler.micrometer.otlp.url=http://127.0.0.1:15200/opentelemetry
14371437
profiler.micrometer.otlp.step=30s
1438-
profiler.micrometer.otlp.batchSize=50
1438+
profiler.micrometer.otlp.batchSize=10000
14391439

agent-module/agent/src/main/resources/profiles/release/pinpoint.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1458,4 +1458,4 @@ profiler.resilience4j.mark.error.circuit-breaker=false
14581458
profiler.micrometer.otlp.enabled=true
14591459
profiler.micrometer.otlp.url=http://127.0.0.1:15200/opentelemetry
14601460
profiler.micrometer.otlp.step=30s
1461-
profiler.micrometer.otlp.batchSize=50
1461+
profiler.micrometer.otlp.batchSize=10000

collector-starter/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@
6868
<groupId>com.navercorp.pinpoint</groupId>
6969
<artifactId>pinpoint-exceptiontrace-collector</artifactId>
7070
</dependency>
71+
<dependency>
72+
<groupId>com.navercorp.pinpoint</groupId>
73+
<artifactId>pinpoint-otlpmetric-collector</artifactId>
74+
</dependency>
7175
</dependencies>
7276

7377
<build>

collector-starter/src/main/java/com/navercorp/pinpoint/collector/starter/multi/application/PinpointCollectorStarter.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.navercorp.pinpoint.inspector.collector.InspectorCollectorConfig;
1818
import com.navercorp.pinpoint.log.collector.LogCollectorModule;
1919
import com.navercorp.pinpoint.metric.collector.MetricCollectorApp;
20+
import com.navercorp.pinpoint.otlp.collector.OtlpMetricCollectorConfig;
2021
import com.navercorp.pinpoint.redis.RedisPropertySources;
2122
import com.navercorp.pinpoint.uristat.collector.UriStatCollectorConfig;
2223
import org.springframework.boot.Banner;
@@ -79,7 +80,9 @@ public static void main(String[] args) {
7980

8081
if (types.hasType(CollectorType.METRIC)) {
8182
logger.info(String.format("Start %s collector", CollectorType.METRIC));
82-
SpringApplicationBuilder metricAppBuilder = createAppBuilder(builder, 15200, MetricCollectorApp.class);
83+
SpringApplicationBuilder metricAppBuilder = createAppBuilder(builder, 15200,
84+
MetricCollectorApp.class,
85+
OtlpMetricCollectorConfig.class);
8386
metricAppBuilder.listeners(new AdditionalProfileListener("metric"));
8487
metricAppBuilder.build().run(args);
8588
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.navercorp.pinpoint.collector.service;
2+
3+
import jakarta.validation.Valid;
4+
5+
public interface OtlpMetricService {
6+
void save(@Valid Object data);
7+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>com.navercorp.pinpoint</groupId>
8+
<artifactId>pinpoint-otlpmetric</artifactId>
9+
<version>3.0.0-SNAPSHOT</version>
10+
</parent>
11+
12+
<artifactId>pinpoint-otlpmetric-collector</artifactId>
13+
<properties>
14+
<jdk.version>17</jdk.version>
15+
<jdk.home>${env.JAVA_17_HOME}</jdk.home>
16+
</properties>
17+
<dependencies>
18+
<dependency>
19+
<groupId>org.springframework</groupId>
20+
<artifactId>spring-context</artifactId>
21+
<version>6.0.13</version>
22+
</dependency>
23+
<dependency>
24+
<groupId>com.navercorp.pinpoint</groupId>
25+
<artifactId>pinpoint-pinot-config</artifactId>
26+
</dependency>
27+
<dependency>
28+
<groupId>com.navercorp.pinpoint</groupId>
29+
<artifactId>pinpoint-pinot-kafka</artifactId>
30+
</dependency>
31+
<dependency>
32+
<groupId>io.opentelemetry.proto</groupId>
33+
<artifactId>opentelemetry-proto</artifactId>
34+
<version>0.19.0-alpha</version>
35+
</dependency>
36+
<dependency>
37+
<groupId>org.springframework</groupId>
38+
<artifactId>spring-web</artifactId>
39+
</dependency>
40+
<dependency>
41+
<groupId>jakarta.validation</groupId>
42+
<artifactId>jakarta.validation-api</artifactId>
43+
</dependency>
44+
<dependency>
45+
<groupId>com.navercorp.pinpoint</groupId>
46+
<artifactId>pinpoint-commons-server</artifactId>
47+
</dependency>
48+
<dependency>
49+
<groupId>org.springframework</groupId>
50+
<artifactId>spring-webmvc</artifactId>
51+
</dependency>
52+
<dependency>
53+
<groupId>com.navercorp.pinpoint</groupId>
54+
<artifactId>pinpoint-otlpmetric-common</artifactId>
55+
</dependency>
56+
</dependencies>
57+
58+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2024 NAVER Corp.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.navercorp.pinpoint.otlp.collector;
18+
19+
import com.navercorp.pinpoint.pinot.config.PinotConfiguration;
20+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
21+
import org.springframework.context.annotation.ComponentScan;
22+
import org.springframework.context.annotation.Configuration;
23+
import org.springframework.context.annotation.Import;
24+
import org.springframework.context.annotation.PropertySource;
25+
26+
@Configuration
27+
@Import({
28+
WebMvcConfig.class,
29+
PinotConfiguration.class,
30+
OtlpMetricKafkaConfiguration.class})
31+
@ComponentScan({
32+
"com.navercorp.pinpoint.otlp.collector.controller",
33+
"com.navercorp.pinpoint.otlp.collector.dao",
34+
"com.navercorp.pinpoint.otlp.collector.service",
35+
"com.navercorp.pinpoint.otlp.collector.mapper",
36+
})
37+
@PropertySource({OtlpMetricCollectorConfig.KAFKA_TOPIC_PROPERTIES})
38+
@ConditionalOnProperty(name = "pinpoint.modules.collector.otlpmetric.enabled", havingValue = "true")
39+
public class OtlpMetricCollectorConfig {
40+
public static final String KAFKA_TOPIC_PROPERTIES = "classpath:profiles/${pinpoint.profiles.active}/kafka-topic-otlpmetric.properties";
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2024 NAVER Corp.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.navercorp.pinpoint.otlp.collector;
18+
19+
import com.navercorp.pinpoint.otlp.collector.model.PinotOtlpMetricDataRow;
20+
import com.navercorp.pinpoint.pinot.kafka.KafkaConfiguration;
21+
import org.springframework.beans.factory.annotation.Qualifier;
22+
import org.springframework.context.annotation.Bean;
23+
import org.springframework.context.annotation.Configuration;
24+
import org.springframework.context.annotation.Import;
25+
import org.springframework.kafka.core.KafkaTemplate;
26+
import org.springframework.kafka.core.ProducerFactory;
27+
28+
@Configuration
29+
@Import({KafkaConfiguration.class})
30+
public class OtlpMetricKafkaConfiguration {
31+
@Bean
32+
public KafkaTemplate<String, PinotOtlpMetricDataRow> kafkaOtlpMetricTemplate(
33+
@Qualifier("kafkaProducerFactory") ProducerFactory producerFactory
34+
) {
35+
return new KafkaTemplate<String, PinotOtlpMetricDataRow>(producerFactory);
36+
}
37+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2024 NAVER Corp.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.navercorp.pinpoint.otlp.collector;
18+
19+
import org.springframework.context.annotation.Configuration;
20+
import org.springframework.http.converter.HttpMessageConverter;
21+
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
22+
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
23+
24+
import java.util.List;
25+
26+
@Configuration
27+
public class WebMvcConfig implements WebMvcConfigurer {
28+
29+
@Override
30+
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
31+
ProtobufHttpMessageConverter protobufHttpMessageConverter = new ProtobufHttpMessageConverter();
32+
converters.add(protobufHttpMessageConverter);
33+
}
34+
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright 2022 NAVER Corp.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.navercorp.pinpoint.otlp.collector.controller;
18+
19+
import com.navercorp.pinpoint.otlp.collector.mapper.OtlpMetricMapper;
20+
import com.navercorp.pinpoint.otlp.collector.model.OtlpMetricData;
21+
import com.navercorp.pinpoint.otlp.collector.service.OtlpMetricService;
22+
import com.navercorp.pinpoint.pinot.tenant.TenantProvider;
23+
import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest;
24+
import io.opentelemetry.proto.common.v1.KeyValue;
25+
import io.opentelemetry.proto.metrics.v1.Metric;
26+
import io.opentelemetry.proto.metrics.v1.ResourceMetrics;
27+
import io.opentelemetry.proto.metrics.v1.ScopeMetrics;
28+
import jakarta.validation.Valid;
29+
import jakarta.validation.constraints.NotNull;
30+
import org.apache.logging.log4j.LogManager;
31+
import org.apache.logging.log4j.Logger;
32+
import org.springframework.http.ResponseEntity;
33+
import org.springframework.web.bind.annotation.PostMapping;
34+
import org.springframework.web.bind.annotation.RequestBody;
35+
import org.springframework.web.bind.annotation.RestController;
36+
37+
import java.util.HashMap;
38+
import java.util.List;
39+
import java.util.Map;
40+
import java.util.Objects;
41+
42+
@RestController
43+
public class OpenTelemetryMetricController {
44+
private final Logger logger = LogManager.getLogger(this.getClass());
45+
46+
private final String tenantId;
47+
@NotNull private final OtlpMetricService otlpMetricService;
48+
@NotNull private final OtlpMetricMapper otlpMetricMapper;
49+
50+
public OpenTelemetryMetricController(TenantProvider tenantProvider,
51+
@Valid OtlpMetricService otlpMetricService,
52+
@Valid OtlpMetricMapper otlpMetricDataMapper) {
53+
Objects.requireNonNull(tenantProvider, "tenantProvider");
54+
this.tenantId = tenantProvider.getTenantId();
55+
this.otlpMetricService = Objects.requireNonNull(otlpMetricService, "otlpMetricService");
56+
this.otlpMetricMapper = Objects.requireNonNull(otlpMetricDataMapper, "otlpMetricDataMapper");
57+
this.otlpMetricMapper.setTenantId(tenantId);
58+
}
59+
60+
@PostMapping(value = "/opentelemetry", consumes = "application/x-protobuf")
61+
public ResponseEntity<Void> saveOtelMetric(@RequestBody ExportMetricsServiceRequest otlp) {
62+
List<ResourceMetrics> resourceMetricsList = otlp.getResourceMetricsList();
63+
64+
for (ResourceMetrics resourceMetrics : resourceMetricsList) {
65+
List<KeyValue> attributesList = resourceMetrics.getResource().getAttributesList();
66+
Map<String, String> tags = convertToMap(attributesList);
67+
68+
List<ScopeMetrics> scopeMetricsList = resourceMetrics.getScopeMetricsList();
69+
for (ScopeMetrics scopeMetrics : scopeMetricsList) {
70+
List<Metric> metricList = scopeMetrics.getMetricsList();
71+
for (Metric metric: metricList) {
72+
OtlpMetricData metricData = toMetrics(metric, tags);
73+
otlpMetricService.save(metricData);
74+
75+
if (logger.isDebugEnabled()) {
76+
logger.debug("tenantId:{} serviceNamespace:{} serviceName:{} metricGroupName:{} metricName: {}",
77+
metricData.getTenantId(),
78+
metricData.getServiceNamespace(),
79+
metricData.getServiceName(),
80+
metricData.getMetricGroupName(),
81+
metricData.getMetricName());
82+
}
83+
}
84+
}
85+
}
86+
87+
return ResponseEntity.ok().build();
88+
}
89+
90+
private OtlpMetricData toMetrics(Metric metric, Map<String, String> tags) {
91+
OtlpMetricData otlpMetricData = otlpMetricMapper.map(metric, tags);
92+
return otlpMetricData;
93+
}
94+
95+
private Map<String, String> convertToMap(List<KeyValue> tags) {
96+
Map<String, String> tagMap = new HashMap<>();
97+
for (KeyValue tag : tags) {
98+
tagMap.put(tag.getKey(), tag.getValue().getStringValue());
99+
}
100+
return tagMap;
101+
}
102+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright 2024 NAVER Corp.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.navercorp.pinpoint.otlp.collector.dao;
18+
19+
import com.navercorp.pinpoint.otlp.collector.model.PinotOtlpMetricDataRow;
20+
21+
import java.util.List;
22+
23+
public interface OtlpMetricDao {
24+
void insert(List<PinotOtlpMetricDataRow> data);
25+
}

0 commit comments

Comments
 (0)