diff --git a/pom.xml b/pom.xml index 88b5cfe31..7765d69e7 100644 --- a/pom.xml +++ b/pom.xml @@ -99,6 +99,7 @@ 1.5.10 6.2.2.Final 1.3.2 + 0.16.0 1.14.3 0.10.7 9.1.6 @@ -114,6 +115,7 @@ 1.2.17 2.17.1 1.7.36 + 9.0.108 false @@ -378,6 +380,29 @@ druid-spring-boot-starter ${druid-spring-boot-starter.version} + + + io.prometheus + simpleclient + ${prometheus.simpleclient.version} + + + io.prometheus + simpleclient_common + ${prometheus.simpleclient.version} + + + + io.prometheus + simpleclient_hotspot + ${prometheus.simpleclient.version} + + + + io.prometheus + simpleclient_httpserver + ${prometheus.simpleclient.version} + org.hibernate.validator @@ -549,6 +574,12 @@ compile + + org.apache.tomcat.embed + tomcat-embed-core + ${tomcat-embed-core.version} + + org.apache.seatunnel datasource-s3 diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-db2/pom.xml b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-db2/pom.xml index a13423735..881f03151 100644 --- a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-db2/pom.xml +++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-db2/pom.xml @@ -63,10 +63,6 @@ db2jcc db2jcc4 - - org.apache.seatunnel - seatunnel-api - diff --git a/seatunnel-server/seatunnel-app/pom.xml b/seatunnel-server/seatunnel-app/pom.xml index cc7578e1f..59d4fa3ae 100644 --- a/seatunnel-server/seatunnel-app/pom.xml +++ b/seatunnel-server/seatunnel-app/pom.xml @@ -325,6 +325,11 @@ spring-security-ldap + + org.springframework.boot + spring-boot-starter-aop + + com.baomidou mybatis-plus-boot-starter @@ -391,6 +396,24 @@ h2 + + + io.prometheus + simpleclient + + + io.prometheus + simpleclient_common + + + io.prometheus + simpleclient_hotspot + + + io.prometheus + simpleclient_httpserver + + org.springframework.boot spring-boot-starter-test @@ -440,6 +463,11 @@ + + org.apache.tomcat.embed + tomcat-embed-core + + org.apache.seatunnel datasource-kafka diff --git a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/adapter/SeatunnelWebAdapter.java b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/adapter/SeatunnelWebAdapter.java index 0974e4562..8b81a90eb 100644 --- a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/adapter/SeatunnelWebAdapter.java +++ b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/adapter/SeatunnelWebAdapter.java @@ -44,6 +44,7 @@ public class SeatunnelWebAdapter implements WebMvcConfigurer { public static final String REGISTER_PATH_PATTERN = "/users/register"; private static final String RESOURCE_NAME_PATH_PATTERN = "/seatunnel/api/v1/resources/workspace"; + private static final String METRIC_PATH_PATTERN = "/metrics"; @Bean public AuthenticationInterceptor authenticationInterceptor() { @@ -77,6 +78,7 @@ public void addInterceptors(InterceptorRegistry registry) { LOGIN_PATH_PATTERN, REGISTER_PATH_PATTERN, RESOURCE_NAME_PATH_PATTERN, + METRIC_PATH_PATTERN, "/swagger-resources/**", "/webjars/**", "/v2/**", diff --git a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/JobDefinitionController.java b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/JobDefinitionController.java index 3da3bf7ca..d9bb2766b 100644 --- a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/JobDefinitionController.java +++ b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/JobDefinitionController.java @@ -22,6 +22,8 @@ import org.apache.seatunnel.app.domain.request.job.JobReq; import org.apache.seatunnel.app.domain.response.PageInfo; import org.apache.seatunnel.app.domain.response.job.JobDefinitionRes; +import org.apache.seatunnel.app.metrics.annotations.Counted; +import org.apache.seatunnel.app.metrics.annotations.Timed; import org.apache.seatunnel.app.service.IJobDefinitionService; import org.apache.seatunnel.app.service.IJobTaskService; import org.apache.seatunnel.server.common.CodeGenerateUtils; @@ -54,6 +56,12 @@ public class JobDefinitionController { * * @return created job id */ + @Counted( + name = "create_job_definition_request", + help = "Total number of create job definition requests") + @Timed( + name = "create_job_definition_request_latency", + help = "Latency of create job definition API in seconds") @PostMapping @ApiOperation(value = "create job definition", httpMethod = "POST") Result createJobDefinition(@RequestBody JobReq jobReq) @@ -65,6 +73,9 @@ Result createJobDefinition(@RequestBody JobReq jobReq) } } + @Counted( + name = "get_job_definitions_request", + help = "Total number of get job definitions request") @GetMapping @ApiOperation(value = "get job definition", httpMethod = "GET") Result> getJobDefinition( @@ -75,12 +86,21 @@ Result> getJobDefinition( return Result.success(jobService.getJob(searchName, pageNo, pageSize, jobMode)); } + @Counted( + name = "get_job_definition_by_id_request", + help = "Total number of get job definition by id requests") @GetMapping("/{jobId}") @ApiOperation(value = "get job definition", httpMethod = "GET") Result getJobDefinition(@PathVariable long jobId) { return Result.success(jobService.getJobDefinitionByJobId(jobId)); } + @Counted( + name = "delete_job_definition_request", + help = "Total number of delete job definition requests") + @Timed( + name = "delete_job_definition_request_latency", + help = "Latency of delete job definition API in seconds") @DeleteMapping @ApiOperation(value = "delete job definition", httpMethod = "DELETE") Result deleteJobDefinition( diff --git a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/JobExecutorController.java b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/JobExecutorController.java index b88224288..9393ec9c5 100644 --- a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/JobExecutorController.java +++ b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/JobExecutorController.java @@ -22,6 +22,7 @@ import org.apache.seatunnel.app.domain.request.job.JobExecParam; import org.apache.seatunnel.app.domain.response.executor.JobExecutionStatus; import org.apache.seatunnel.app.domain.response.executor.JobExecutorRes; +import org.apache.seatunnel.app.metrics.annotations.Counted; import org.apache.seatunnel.app.service.IJobExecutorService; import org.apache.seatunnel.app.service.IJobInstanceService; import org.apache.seatunnel.app.service.ITaskInstanceService; @@ -53,6 +54,7 @@ public class JobExecutorController { @Resource private IJobInstanceService jobInstanceService; @Resource private ITaskInstanceService taskInstanceService; + @Counted(name = "execute_job_request", help = "Total number of execute job requests") @PostMapping("/execute") @ApiOperation(value = "Execute synchronization tasks", httpMethod = "POST") public Result jobExecutor( @@ -77,6 +79,7 @@ public Result resource( } } + @Counted(name = "pause_job_request", help = "Total number of pause job requests") @GetMapping("/pause") public Result jobPause( @ApiParam(value = "jobInstanceId", required = true) @RequestParam Long jobInstanceId) { diff --git a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/JobTaskController.java b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/JobTaskController.java index 0e2fd1e9f..49d81c0ee 100644 --- a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/JobTaskController.java +++ b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/JobTaskController.java @@ -22,6 +22,8 @@ import org.apache.seatunnel.app.domain.request.job.JobTaskInfo; import org.apache.seatunnel.app.domain.request.job.PluginConfig; import org.apache.seatunnel.app.domain.response.job.JobTaskCheckRes; +import org.apache.seatunnel.app.metrics.annotations.Counted; +import org.apache.seatunnel.app.metrics.annotations.Timed; import org.apache.seatunnel.app.service.IJobTaskService; import org.springframework.web.bind.annotation.DeleteMapping; @@ -44,6 +46,10 @@ public class JobTaskController { @Resource private IJobTaskService jobTaskService; + @Counted(name = "save_job_dag_request", help = "Total number of save job dag requests") + @Timed( + name = "save_job_dag_request_latency", + help = "Latency of save job dag request in seconds") @PostMapping("/dag/{jobVersionId}") @ApiOperation(value = "save job dag", httpMethod = "POST") Result saveJobDAG( @@ -59,6 +65,10 @@ Result getJob( return Result.success(jobTaskService.getTaskConfig(jobVersionId)); } + @Counted(name = "save_job_task_request", help = "Total number of save job task requests") + @Timed( + name = "save_job_task_request_latency", + help = "Latency of save job task request in seconds") @PostMapping("/task/{jobVersionId}") @ApiOperation(value = "save or update single task", httpMethod = "POST") Result saveSingleTask( @@ -77,6 +87,10 @@ Result getSingleTask( return Result.success(jobTaskService.getSingleTask(jobVersionId, pluginId)); } + @Counted(name = "delete_job_task_request", help = "Total number of delete job task requests") + @Timed( + name = "delete_job_task_request_latency", + help = "Latency of delete job task request in seconds") @DeleteMapping("/task/{jobVersionId}") @ApiOperation(value = "delete single task", httpMethod = "DELETE") Result deleteSingleTask( diff --git a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/SeatunnelDatasourceController.java b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/SeatunnelDatasourceController.java index 85da2ac5a..673c7d381 100644 --- a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/SeatunnelDatasourceController.java +++ b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/SeatunnelDatasourceController.java @@ -29,6 +29,8 @@ import org.apache.seatunnel.app.domain.response.PageInfo; import org.apache.seatunnel.app.domain.response.datasource.DatasourceDetailRes; import org.apache.seatunnel.app.domain.response.datasource.DatasourceRes; +import org.apache.seatunnel.app.metrics.annotations.Counted; +import org.apache.seatunnel.app.metrics.annotations.Timed; import org.apache.seatunnel.app.service.IDatasourceService; import org.apache.seatunnel.app.utils.CartesianProductUtils; import org.apache.seatunnel.app.utils.PropertyUtils; @@ -80,6 +82,8 @@ public class SeatunnelDatasourceController extends BaseController { private static final List wsSupportDatasources = PropertyUtils.getList(Constants.WS_SUPPORT_DATASOURCES, Constants.COMMA); + @Counted(name = "create_datasource_requests", help = "Number of create datasource requests") + @Timed(name = "create_datasource_latency", help = "Latency of create datasource API") @ApiOperation(value = "create datasource", notes = "create datasource") @ApiImplicitParams({ @ApiImplicitParam( @@ -120,6 +124,10 @@ Result createDatasource(@RequestBody DatasourceReq req) { stringStringMap)); } + @Counted( + name = "test_connection_requests", + help = "Number of test datasource connection requests") + @Timed(name = "test_connection_latency", help = "Latency of check datasource connection API") @ApiOperation(value = "test datasource connection", notes = "test datasource connection") @ApiImplicitParams({ @ApiImplicitParam( @@ -142,6 +150,8 @@ Result testConnect(@RequestBody DatasourceCheckReq req) { req.getPluginName(), DEFAULT_PLUGIN_VERSION, req.getDatasourceConfig())); } + @Counted(name = "update_datasource_requests", help = "Number of update datasource requests") + @Timed(name = "update_datasource_latency", help = "Latency of update datasource API") @ApiOperation(value = "update datasource", notes = "update datasource") @ApiImplicitParams({ @ApiImplicitParam( @@ -176,6 +186,8 @@ Result updateDatasource( stringStringMap)); } + @Counted(name = "delete_datasource_requests", help = "Number of delete datasource requests") + @Timed(name = "delete_datasource_latency", help = "Latency of delete datasource API") @ApiOperation(value = "delete datasource by id", notes = "delete datasource by id") @DeleteMapping("/{id}") Result deleteDatasource(@PathVariable("id") String id) { diff --git a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/TaskInstanceController.java b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/TaskInstanceController.java index 128c2e61b..acbab8826 100644 --- a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/TaskInstanceController.java +++ b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/TaskInstanceController.java @@ -19,6 +19,8 @@ import org.apache.seatunnel.app.common.Result; import org.apache.seatunnel.app.domain.dto.job.SeaTunnelJobInstanceDto; +import org.apache.seatunnel.app.metrics.annotations.Counted; +import org.apache.seatunnel.app.metrics.annotations.Timed; import org.apache.seatunnel.app.service.ITaskInstanceService; import org.apache.seatunnel.app.utils.PageInfo; import org.apache.seatunnel.common.constants.JobMode; @@ -37,6 +39,8 @@ public class TaskInstanceController { @Autowired ITaskInstanceService taskInstanceService; + @Counted(name = "number_of_job_metric_request", help = "total number of job metrics request") + @Timed(name = "job_metric_request_latency", help = "Latency of job metric api in seconds") @GetMapping("/jobMetrics") @ApiOperation(value = "get the jobMetrics list ", httpMethod = "GET") public Result> getTaskInstanceList( diff --git a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/UserController.java b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/UserController.java index 59c68ab4b..cf1ff2e0f 100644 --- a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/UserController.java +++ b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/UserController.java @@ -25,6 +25,8 @@ import org.apache.seatunnel.app.domain.response.PageInfo; import org.apache.seatunnel.app.domain.response.user.AddUserRes; import org.apache.seatunnel.app.domain.response.user.UserSimpleInfoRes; +import org.apache.seatunnel.app.metrics.annotations.Counted; +import org.apache.seatunnel.app.metrics.annotations.Timed; import org.apache.seatunnel.app.service.IUserService; import org.springframework.web.bind.annotation.DeleteMapping; @@ -110,6 +112,8 @@ public Result disable( return Result.success(); } + @Counted(name = "user_login", help = "total number of user login request") + @Timed(name = "user_login_request_latency", help = "Latency of login request in seconds") @PostMapping("/login") public Result login( @RequestBody UserLoginReq req, diff --git a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/annotations/Counted.java b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/annotations/Counted.java new file mode 100644 index 000000000..bce1ecfe2 --- /dev/null +++ b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/annotations/Counted.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.seatunnel.app.metrics.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Counted { + String name(); + + String help() default ""; +} diff --git a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/annotations/Timed.java b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/annotations/Timed.java new file mode 100644 index 000000000..e8fe2ad09 --- /dev/null +++ b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/annotations/Timed.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.seatunnel.app.metrics.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Timed { + String name(); + + String help() default ""; +} diff --git a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/aop/MetricsAspect.java b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/aop/MetricsAspect.java new file mode 100644 index 000000000..3833dcd17 --- /dev/null +++ b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/aop/MetricsAspect.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.seatunnel.app.metrics.aop; + +import org.apache.seatunnel.app.metrics.annotations.Counted; +import org.apache.seatunnel.app.metrics.annotations.Timed; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; + +import io.prometheus.client.CollectorRegistry; +import io.prometheus.client.Counter; +import io.prometheus.client.Summary; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Aspect +@Component +@ConditionalOnProperty(name = "seatunnel-web.telemetry.enabled", havingValue = "true") +public class MetricsAspect { + + private final CollectorRegistry collectorRegistry; + + private final Map counters = new ConcurrentHashMap<>(); + private final Map summaries = new ConcurrentHashMap<>(); + + @Autowired + public MetricsAspect(CollectorRegistry collectorRegistry) { + this.collectorRegistry = collectorRegistry; + } + + @Before("@annotation(counted)") + public void beforeCounted(Counted counted) { + String name = counted.name(); + String help = counted.help(); + + Counter counter = + counters.computeIfAbsent( + name, + key -> + Counter.build() + .name(key) + .help(help.isEmpty() ? "Counter for " + key : help) + .register(collectorRegistry)); + + counter.inc(); + } + + @Around("@annotation(timed)") + public Object aroundTimed(ProceedingJoinPoint joinPoint, Timed timed) throws Throwable { + String name = timed.name(); + String help = timed.help(); + + Summary summary = + summaries.computeIfAbsent( + name, + key -> + Summary.build() + .name(key) + .help(help.isEmpty() ? "Summary for " + key : help) + .register(collectorRegistry)); + + try (Summary.Timer ignored = summary.startTimer()) { + return joinPoint.proceed(); + } + } +} diff --git a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/config/MetricsFilter.java b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/config/MetricsFilter.java new file mode 100644 index 000000000..fcce318a4 --- /dev/null +++ b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/config/MetricsFilter.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.seatunnel.app.metrics.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; + +import java.io.IOException; + +@Component +public class MetricsFilter implements Filter { + + @Value("${seatunnel-web.telemetry.port:8802}") + private String telemetryPort; + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + HttpServletRequest httpRequest = (HttpServletRequest) request; + if (httpRequest.getLocalPort() == Integer.parseInt(telemetryPort) + && "/metrics".equals(httpRequest.getRequestURI())) { + chain.doFilter(request, response); // Allow metrics requests + } else if (httpRequest.getLocalPort() == Integer.parseInt(telemetryPort)) { + response.getWriter().write("Access Denied"); + response.getWriter().flush(); + } else { + chain.doFilter(request, response); // Allow other requests on the default port + } + } +} diff --git a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/config/MetricsPortConfig.java b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/config/MetricsPortConfig.java new file mode 100644 index 000000000..1a32bc69e --- /dev/null +++ b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/config/MetricsPortConfig.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.seatunnel.app.metrics.config; + +import org.apache.catalina.connector.Connector; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class MetricsPortConfig { + + @Value("${seatunnel-web.telemetry.port:8802}") + private String telemetryPort; + + @Bean + public WebServerFactoryCustomizer metricsConnectorCustomizer() { + return factory -> { + Connector metricsConnector = + new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL); + metricsConnector.setPort( + Integer.parseInt(telemetryPort)); // Set the desired port for metrics + factory.addAdditionalTomcatConnectors(metricsConnector); + }; + } +} diff --git a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/config/PrometheusConfig.java b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/config/PrometheusConfig.java new file mode 100644 index 000000000..645328e15 --- /dev/null +++ b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/config/PrometheusConfig.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.seatunnel.app.metrics.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import io.prometheus.client.CollectorRegistry; +import io.prometheus.client.hotspot.DefaultExports; + +import javax.annotation.PostConstruct; + +@Configuration +@ConditionalOnProperty(name = "seatunnel-web.telemetry.enabled", havingValue = "true") +public class PrometheusConfig { + + @PostConstruct + public void init() { + DefaultExports.initialize(); + } + + @Bean + public CollectorRegistry collectorRegistry() { + return CollectorRegistry.defaultRegistry; + } +} diff --git a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/controller/MetricsController.java b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/controller/MetricsController.java new file mode 100644 index 000000000..713b487ed --- /dev/null +++ b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/metrics/controller/MetricsController.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.seatunnel.app.metrics.controller; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import io.prometheus.client.CollectorRegistry; +import io.prometheus.client.exporter.common.TextFormat; + +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.io.Writer; + +@RestController +@ConditionalOnProperty(name = "seatunnel-web.telemetry.enabled", havingValue = "true") +public class MetricsController { + + private final CollectorRegistry collectorRegistry; + + public MetricsController(CollectorRegistry collectorRegistry) { + this.collectorRegistry = collectorRegistry; + } + + @GetMapping("/metrics") + public void scrape(HttpServletResponse response) throws IOException { + response.setContentType(TextFormat.CONTENT_TYPE_004); + try (Writer writer = response.getWriter()) { + TextFormat.write004(writer, collectorRegistry.metricFamilySamples()); + } + } +} diff --git a/seatunnel-server/seatunnel-app/src/main/resources/application.yml b/seatunnel-server/seatunnel-app/src/main/resources/application.yml index 57117794e..e67dd0c9b 100644 --- a/seatunnel-server/seatunnel-app/src/main/resources/application.yml +++ b/seatunnel-server/seatunnel-app/src/main/resources/application.yml @@ -60,6 +60,9 @@ seatunnel-web: - password - auth access-controller-class: org.apache.seatunnel.app.permission.SeatunnelAccessControllerDefaultImpl + telemetry: + enabled: false + port: 8802 --- spring: config: diff --git a/seatunnel-web-it/src/test/resources/application.yml b/seatunnel-web-it/src/test/resources/application.yml index d691a7127..bf258a084 100644 --- a/seatunnel-web-it/src/test/resources/application.yml +++ b/seatunnel-web-it/src/test/resources/application.yml @@ -56,6 +56,9 @@ seatunnel-web: - password - auth access-controller-class: org.apache.seatunnel.app.common.AccessControllerTestingImp + telemetry: + enabled: false + port: 8803 --- spring: diff --git a/tools/dependencies/known-dependencies.txt b/tools/dependencies/known-dependencies.txt index d9b7e900e..89c1f7452 100644 --- a/tools/dependencies/known-dependencies.txt +++ b/tools/dependencies/known-dependencies.txt @@ -168,7 +168,8 @@ simpleclient_httpserver-0.16.0.jar simpleclient_tracer_common-0.16.0.jar simpleclient_tracer_otel-0.16.0.jar simpleclient_tracer_otel_agent-0.16.0.jar - +tomcat-annotations-api-9.0.108.jar +tomcat-embed-core-9.0.108.jar