├── README.md ├── .idea ├── vcs.xml └── .gitignore ├── src └── main │ ├── java │ └── io │ │ └── bitdive │ │ └── mcpserver │ │ ├── dto │ │ ├── hierarchy_method │ │ │ ├── data │ │ │ │ ├── FindClassAndMethodBetweenDateDTO.java │ │ │ │ ├── MessageKafkaParentMethodUIDto.java │ │ │ │ ├── ModuleUIDto.java │ │ │ │ ├── ModuleRepositoryDTO.java │ │ │ │ ├── InPointUIDto.java │ │ │ │ ├── ClassNameUIDto.java │ │ │ │ ├── ServiceUIDto.java │ │ │ │ ├── MessageKafkaCallTimeUIDto.java │ │ │ │ ├── CallMethodQueueSendRepositoryDTO.java │ │ │ │ ├── CallMethodUIDto.java │ │ │ │ ├── CallMethodSqlRepositoryDTO.java │ │ │ │ ├── CallMethodQueueSendDTO.java │ │ │ │ ├── CallMethodSqlDTO.java │ │ │ │ ├── CallMethodRestDTO.java │ │ │ │ ├── CallMethodRestRepositoryDTO.java │ │ │ │ ├── CallMethodRepositoryDTO.java │ │ │ │ └── CallMethodDTO.java │ │ │ ├── HierarchyMethodAlertUI.java │ │ │ ├── CallNodeUIDto.java │ │ │ ├── SQLCall.java │ │ │ ├── QueueCall.java │ │ │ ├── RestCall.java │ │ │ ├── HierarchyMethodUIDto.java │ │ │ └── heap_map │ │ │ │ ├── InPointAnalyticsDTO.java │ │ │ │ ├── ClassAnalyticsDTO.java │ │ │ │ ├── ModuleAnalyticsDTO.java │ │ │ │ ├── ServiceAnalyticsDTO.java │ │ │ │ └── AnalyticsBaseDTO.java │ │ └── last_call │ │ │ ├── LastCallModuleAndServiceDTO.java │ │ │ └── LastCallReturn.java │ │ ├── db │ │ ├── entity │ │ │ ├── CallMethodQueueSendEntity.java │ │ │ ├── CallMethodSql.java │ │ │ ├── CallMethodRest.java │ │ │ ├── ServiceNodeForModule.java │ │ │ ├── CallMethod.java │ │ │ ├── ModuleCallAnalytics.java │ │ │ ├── ServiceCallAnalytics.java │ │ │ ├── ClassCallAnalytics.java │ │ │ └── InPointCallAnalytics.java │ │ └── repository │ │ │ ├── ClassCallAnalyticsRepository.java │ │ │ ├── ModuleCallAnalyticsRepository.java │ │ │ ├── InPointCallAnalyticsRepository.java │ │ │ ├── ServiceCallAnalyticsRepository.java │ │ │ ├── ServiceNodeForModuleRepository.java │ │ │ ├── CallMethodSqlRepository.java │ │ │ ├── CallMethodQueueSendRepository.java │ │ │ ├── CallMethodRestRepository.java │ │ │ └── CallMethodRepository.java │ │ ├── McpServerApplication.java │ │ ├── utils │ │ ├── UserViewModule.java │ │ ├── HierarchySearcher.java │ │ ├── FinalConvertObject.java │ │ ├── HierarchyUtils.java │ │ ├── CallMethodConverter.java │ │ └── UtilsCovert.java │ │ ├── config │ │ ├── ToolCallbackConfig.java │ │ └── McpKeepAliveConfig.java │ │ ├── component │ │ ├── PiiMaskClientComponent.java │ │ ├── LastCallComponent.java │ │ ├── MonitoringHeapMapComponent.java │ │ ├── MonitoringComponent.java │ │ ├── InPointProvider.java │ │ └── AnalyticsService.java │ │ └── service │ │ ├── LastCallTools.java │ │ ├── TraceTools.java │ │ └── HeadMapTools.java │ └── resources │ └── application.yml ├── HELP.md ├── pom.xml ├── mvnw.cmd ├── mvnw └── LICENSE /README.md: -------------------------------------------------------------------------------- 1 | # mcp-server 2 | bitdive mcp server for conenction with AI 3 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/data/FindClassAndMethodBetweenDateDTO.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.data; 2 | 3 | import java.util.UUID; 4 | 5 | public interface FindClassAndMethodBetweenDateDTO { 6 | UUID getInPointMessageId(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/data/MessageKafkaParentMethodUIDto.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.data; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Getter 7 | @Setter 8 | public class MessageKafkaParentMethodUIDto { 9 | private String UUIDParent; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/HierarchyMethodAlertUI.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | 6 | @Getter 7 | @Builder 8 | public class HierarchyMethodAlertUI { 9 | private String alertValue=null; 10 | private Boolean alertMeaning=false; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/data/ModuleUIDto.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.data; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | import java.util.Set; 7 | 8 | @Getter 9 | @AllArgsConstructor 10 | public class ModuleUIDto { 11 | private String name; 12 | private Set serviceUI; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/data/ModuleRepositoryDTO.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.data; 2 | 3 | public interface ModuleRepositoryDTO { 4 | 5 | String getModule(); 6 | 7 | String getService(); 8 | 9 | String getClassName(); 10 | 11 | String getMethod(); 12 | 13 | Boolean getIsInPoint(); 14 | 15 | Long getInPointId(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/CallNodeUIDto.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | import java.util.List; 8 | 9 | @Getter 10 | @Setter 11 | @Builder 12 | public class CallNodeUIDto { 13 | private String methodName; 14 | private String className; 15 | private Double callTime; 16 | private List children; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/data/InPointUIDto.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.data; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.Getter; 6 | 7 | @Getter 8 | @EqualsAndHashCode 9 | @AllArgsConstructor 10 | public class InPointUIDto { 11 | @EqualsAndHashCode.Exclude 12 | private Long inPointId; 13 | private String inPointName; 14 | private Boolean IsInPoint; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/data/ClassNameUIDto.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.data; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.Getter; 6 | 7 | import java.util.Set; 8 | 9 | @Getter 10 | @AllArgsConstructor 11 | @EqualsAndHashCode 12 | public class ClassNameUIDto { 13 | @EqualsAndHashCode.Exclude 14 | private String name; 15 | private Set inPointUI; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/data/ServiceUIDto.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.data; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.Getter; 6 | 7 | import java.util.Set; 8 | 9 | @Getter 10 | @AllArgsConstructor 11 | @EqualsAndHashCode 12 | public class ServiceUIDto { 13 | @EqualsAndHashCode.Exclude 14 | private String name; 15 | private Set classNameUI; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/last_call/LastCallModuleAndServiceDTO.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.last_call; 2 | 3 | import java.time.Instant; 4 | import java.util.UUID; 5 | 6 | public interface LastCallModuleAndServiceDTO { 7 | public UUID getMessageId(); 8 | 9 | public String getModuleName(); 10 | 11 | public String getServiceName(); 12 | 13 | public String getClassName(); 14 | 15 | public String getMethodName(); 16 | 17 | public Instant getCallDateTime(); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/entity/CallMethodQueueSendEntity.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.entity; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.Id; 5 | import jakarta.persistence.Table; 6 | import org.hibernate.annotations.JdbcTypeCode; 7 | import org.hibernate.type.SqlTypes; 8 | 9 | import java.util.UUID; 10 | 11 | @Entity 12 | @Table(name = "call_method_queue_send") 13 | public class CallMethodQueueSendEntity { 14 | @Id 15 | @JdbcTypeCode(SqlTypes.CHAR) 16 | private UUID id; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/repository/ClassCallAnalyticsRepository.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.repository; 2 | 3 | import io.bitdive.mcpserver.db.entity.ClassCallAnalytics; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.time.OffsetDateTime; 7 | import java.util.List; 8 | 9 | public interface ClassCallAnalyticsRepository extends JpaRepository { 10 | List findByAnalysisTimestampBetween(OffsetDateTime start, OffsetDateTime end); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/entity/CallMethodSql.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.entity; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.Id; 5 | import jakarta.persistence.Table; 6 | import lombok.Getter; 7 | import org.hibernate.annotations.JdbcTypeCode; 8 | import org.hibernate.type.SqlTypes; 9 | 10 | import java.util.UUID; 11 | 12 | @Entity 13 | @Getter 14 | @Table(name = "call_method_sql") 15 | public class CallMethodSql { 16 | @Id 17 | @JdbcTypeCode(SqlTypes.CHAR) 18 | private UUID id; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/repository/ModuleCallAnalyticsRepository.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.repository; 2 | 3 | import io.bitdive.mcpserver.db.entity.ModuleCallAnalytics; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.time.OffsetDateTime; 7 | import java.util.List; 8 | 9 | public interface ModuleCallAnalyticsRepository extends JpaRepository { 10 | List findByAnalysisTimestampBetween(OffsetDateTime start, OffsetDateTime end); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/repository/InPointCallAnalyticsRepository.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.repository; 2 | 3 | import io.bitdive.mcpserver.db.entity.InPointCallAnalytics; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.time.OffsetDateTime; 7 | import java.util.List; 8 | 9 | public interface InPointCallAnalyticsRepository extends JpaRepository { 10 | List findByAnalysisTimestampBetween(OffsetDateTime start, OffsetDateTime end); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/entity/CallMethodRest.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.entity; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.Id; 5 | import jakarta.persistence.Table; 6 | import lombok.Getter; 7 | import org.hibernate.annotations.JdbcTypeCode; 8 | import org.hibernate.type.SqlTypes; 9 | 10 | import java.util.UUID; 11 | 12 | @Entity 13 | @Getter 14 | @Table(name = "call_method_rest") 15 | public class CallMethodRest { 16 | @Id 17 | @JdbcTypeCode(SqlTypes.CHAR) 18 | private UUID id; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/repository/ServiceCallAnalyticsRepository.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.repository; 2 | 3 | import io.bitdive.mcpserver.db.entity.ServiceCallAnalytics; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.time.OffsetDateTime; 7 | import java.util.List; 8 | 9 | public interface ServiceCallAnalyticsRepository extends JpaRepository { 10 | List findByAnalysisTimestampBetween(OffsetDateTime start, OffsetDateTime end); 11 | } 12 | 13 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/data/MessageKafkaCallTimeUIDto.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.data; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import java.time.LocalDateTime; 9 | 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | @Getter 13 | @Setter 14 | public class MessageKafkaCallTimeUIDto { 15 | private LocalDateTime dateStart; 16 | private LocalDateTime dateEnd; 17 | private long deltaCall; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/SQLCall.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | 6 | import java.time.OffsetDateTime; 7 | import java.util.UUID; 8 | 9 | @Getter 10 | @Builder 11 | public class SQLCall { 12 | private UUID messageId; 13 | private String sql; 14 | private OffsetDateTime callTimeDateStart; 15 | private OffsetDateTime callTimeDateEnd; 16 | private Double callTimeDelta; 17 | private String errorCallMessage; 18 | private String libraryVersion; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/entity/ServiceNodeForModule.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.entity; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.Id; 5 | import jakarta.persistence.Table; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | import org.hibernate.annotations.JdbcTypeCode; 9 | import org.hibernate.type.SqlTypes; 10 | 11 | import java.util.UUID; 12 | 13 | @Getter 14 | @Setter 15 | @Entity 16 | @Table(name = "service_node_for_module") 17 | public class ServiceNodeForModule { 18 | @Id 19 | @JdbcTypeCode(SqlTypes.CHAR) 20 | private UUID id; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/last_call/LastCallReturn.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.last_call; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | 7 | import java.time.Instant; 8 | import java.time.OffsetDateTime; 9 | import java.util.UUID; 10 | 11 | @AllArgsConstructor 12 | @Getter 13 | public class LastCallReturn { 14 | private UUID traceId; 15 | private String moduleName; 16 | private String serviceName; 17 | private String className; 18 | private String methodName; 19 | private OffsetDateTime callDateTime; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/McpServerApplication.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver; 2 | 3 | import org.springframework.ai.mcp.server.autoconfigure.McpServerAutoConfiguration; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.scheduling.annotation.EnableScheduling; 7 | import reactor.core.publisher.Hooks; 8 | 9 | @SpringBootApplication() 10 | @EnableScheduling 11 | public class McpServerApplication { 12 | public static void main(String[] args) { 13 | SpringApplication.run(McpServerApplication.class, args); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/data/CallMethodQueueSendRepositoryDTO.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.data; 2 | 3 | import java.util.UUID; 4 | 5 | public interface CallMethodQueueSendRepositoryDTO { 6 | UUID getMessageId(); 7 | UUID getSpanId(); 8 | UUID getTraceId(); 9 | UUID getCallIdMessage(); 10 | String getMessageBody(); 11 | String getCallTimeDateStart(); 12 | String getCallTimeDateEnd(); 13 | Long getCallTimeDelta(); 14 | String getQueueServer(); 15 | String getTopicName(); 16 | String getLibraryVersion(); 17 | String getErrorCall(); 18 | Boolean getIsError(); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/data/CallMethodUIDto.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.data; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import java.util.UUID; 7 | 8 | @Getter 9 | @Setter 10 | public class CallMethodUIDto { 11 | private UUID id; 12 | private UUID traceId; 13 | private String className; 14 | private String methodName; 15 | private String args; 16 | private MessageKafkaCallTimeUIDto messageKafkaCallTime; 17 | private MessageKafkaParentMethodUIDto parentMethod; 18 | private String methodReturn; 19 | private String errorCallMessage; 20 | private String libraryVersion; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/QueueCall.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | 6 | import java.time.OffsetDateTime; 7 | import java.util.UUID; 8 | 9 | @Getter 10 | @Builder 11 | public class QueueCall { 12 | private UUID messageId; 13 | private OffsetDateTime callTimeDateStart; 14 | private OffsetDateTime callTimeDateEnd; 15 | private Double callTimeDelta; 16 | private String messageBody; 17 | private String queueTopic; 18 | private String queueServer; 19 | private String libraryVersion; 20 | private String errorCall; 21 | private Boolean isError; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/utils/UserViewModule.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.utils; 2 | 3 | import io.bitdive.mcpserver.config.securety.dto.CurrentUser; 4 | 5 | public class UserViewModule { 6 | public static boolean isViewForModule(CurrentUser currentUser, String moduleName) { 7 | return currentUser.isAdmin() || currentUser.moduleView().stream() 8 | .anyMatch(userModuleView -> userModuleView.equalsIgnoreCase( 9 | moduleName.contains("-") 10 | ? moduleName.substring(0, moduleName.toLowerCase().indexOf("-")) 11 | : moduleName 12 | ) 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/data/CallMethodSqlRepositoryDTO.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.data; 2 | 3 | import java.util.UUID; 4 | 5 | public interface CallMethodSqlRepositoryDTO { 6 | 7 | Integer getId(); 8 | 9 | UUID getSpanId(); 10 | 11 | UUID getTraceId(); 12 | 13 | UUID getMessageId(); 14 | 15 | UUID getCallIdMessage(); 16 | 17 | String getCallMethodSqlText(); 18 | 19 | String getCallMethodSqlParam(); 20 | 21 | String getCallTimeDateStart(); 22 | 23 | String getCallTimeDateEnd(); 24 | 25 | Double getCallTimeDelta(); 26 | 27 | String getErrorCallMessage(); 28 | 29 | String getLibraryVersion(); 30 | 31 | Integer getUrlConnectId(); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/RestCall.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | 6 | import java.time.OffsetDateTime; 7 | import java.util.UUID; 8 | 9 | @Getter 10 | @Builder 11 | public class RestCall { 12 | private UUID messageId; 13 | private String uri; 14 | private OffsetDateTime callTimeDateStart; 15 | private OffsetDateTime callTimeDateEnd; 16 | private Double callTimeDelta; 17 | private String method; 18 | private String headers; 19 | private String body; 20 | private String statusCode; 21 | public String responseHeaders; 22 | public String responseBody; 23 | private String errorCallMessage; 24 | private String libraryVersion; 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/entity/CallMethod.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.entity; 2 | 3 | 4 | import jakarta.persistence.Column; 5 | import jakarta.persistence.Entity; 6 | import jakarta.persistence.Id; 7 | import jakarta.persistence.Table; 8 | import lombok.AllArgsConstructor; 9 | import lombok.Getter; 10 | import lombok.NoArgsConstructor; 11 | import lombok.Setter; 12 | import org.hibernate.annotations.JdbcTypeCode; 13 | import org.hibernate.type.SqlTypes; 14 | 15 | import java.util.UUID; 16 | 17 | @Getter 18 | @Setter 19 | @Entity 20 | @AllArgsConstructor 21 | @NoArgsConstructor 22 | @Table(name = "call_method") 23 | public class CallMethod { 24 | @Id 25 | @JdbcTypeCode(SqlTypes.CHAR) 26 | @Column(name = "message_id", nullable = false) 27 | private UUID id; 28 | } -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/data/CallMethodQueueSendDTO.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.data; 2 | 3 | import lombok.Builder; 4 | import lombok.Data; 5 | 6 | import java.time.OffsetDateTime; 7 | import java.util.UUID; 8 | 9 | @Data 10 | @Builder 11 | public class CallMethodQueueSendDTO { 12 | private UUID messageId; 13 | private UUID spanId; 14 | private UUID traceId; 15 | private UUID callIdMessage; 16 | private String messageBody; 17 | private OffsetDateTime callTimeDateStart; 18 | private OffsetDateTime callTimeDateEnd; 19 | private Long callTimeDelta; 20 | private String queueServer; 21 | private String topicName; 22 | private String libraryVersion; 23 | private String errorCall; 24 | private Boolean isError; 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/data/CallMethodSqlDTO.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.data; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | 6 | import java.time.OffsetDateTime; 7 | import java.util.UUID; 8 | 9 | @Getter 10 | @Builder 11 | public class CallMethodSqlDTO { 12 | private Integer id; 13 | private UUID spanId; 14 | private UUID traceId; 15 | private UUID messageId; 16 | private UUID callIdMessage; 17 | private String callMethodSqlText; 18 | private String callMethodSqlParam; 19 | private OffsetDateTime callTimeDateStart; 20 | private OffsetDateTime callTimeDateEnd; 21 | private Double callTimeDelta; 22 | private String errorCallMessage; 23 | private String libraryVersion; 24 | private Integer urlConnectId; 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/data/CallMethodRestDTO.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.data; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | 6 | import java.time.OffsetDateTime; 7 | import java.util.UUID; 8 | 9 | @Getter 10 | @Builder 11 | public class CallMethodRestDTO { 12 | private UUID traceId; 13 | private UUID spanId; 14 | private UUID messageId; 15 | private UUID callIdMessage; 16 | private OffsetDateTime dateStart; 17 | private OffsetDateTime dateEnd; 18 | private Double callTimeDelta; 19 | private String uri; 20 | private String methodId; 21 | private String headers; 22 | private String body; 23 | private String statusCode; 24 | private String responseHeaders; 25 | private String responseBody; 26 | private String errorCall; 27 | private String libraryVersion; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/config/ToolCallbackConfig.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.config; 2 | 3 | import io.bitdive.mcpserver.service.HeadMapTools; 4 | import io.bitdive.mcpserver.service.LastCallTools; 5 | import io.bitdive.mcpserver.service.TraceTools; 6 | import org.springframework.ai.tool.ToolCallbackProvider; 7 | import org.springframework.ai.tool.method.MethodToolCallbackProvider; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | @Configuration 12 | public class ToolCallbackConfig { 13 | @Bean 14 | public ToolCallbackProvider monitoringTools(TraceTools traceTools, HeadMapTools headMapTools, LastCallTools lastCallTools) { 15 | return MethodToolCallbackProvider.builder() 16 | .toolObjects(traceTools, headMapTools, lastCallTools) 17 | .build(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/data/CallMethodRestRepositoryDTO.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.data; 2 | 3 | import java.util.UUID; 4 | 5 | public interface CallMethodRestRepositoryDTO { 6 | 7 | String getId(); 8 | 9 | UUID getTraceId(); 10 | 11 | UUID getSpanId(); 12 | 13 | UUID getMessageId(); 14 | 15 | UUID getCallIdMessage(); 16 | 17 | String getDateStart(); 18 | 19 | String getDateEnd(); 20 | 21 | Double getCallTimeDelta(); 22 | 23 | String getUrl(); 24 | 25 | String getMethodName(); 26 | 27 | String getHeaders(); 28 | 29 | String getBody(); 30 | 31 | String getResponseHeaders(); 32 | 33 | String getResponseBody(); 34 | 35 | String getStatusCode(); 36 | 37 | String getErrorCall(); 38 | 39 | String getLibraryVersion(); 40 | 41 | String getServiceCallId(); 42 | 43 | } -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/utils/HierarchySearcher.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.utils; 2 | 3 | import io.bitdive.mcpserver.dto.hierarchy_method.HierarchyMethodUIDto; 4 | 5 | import java.util.Optional; 6 | 7 | public class HierarchySearcher { 8 | 9 | public static Optional findInHierarchy( 10 | HierarchyMethodUIDto node, 11 | String className, 12 | String methodName 13 | ) { 14 | if (className.equals(node.getClassName()) && 15 | methodName.equals(node.getMethodName())) { 16 | return Optional.of(node); 17 | } 18 | 19 | for (HierarchyMethodUIDto child : node.getChildCalls()) { 20 | Optional found = findInHierarchy(child, className, methodName); 21 | if (found.isPresent()) { 22 | return found; 23 | } 24 | } 25 | 26 | return Optional.empty(); 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/repository/ServiceNodeForModuleRepository.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.repository; 2 | 3 | import io.bitdive.mcpserver.db.entity.ServiceNodeForModule; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.Query; 6 | 7 | import java.util.Optional; 8 | 9 | public interface ServiceNodeForModuleRepository extends JpaRepository { 10 | @Query(value = """ 11 | select max(snm.id) as id 12 | from service_node_for_module snm 13 | left join module m on snm.module_id=m.id 14 | left join service_for_module sfm on sfm.module_id=snm.module_id and sfm.id=snm.service_id 15 | where lower(m.name)=:moduleName and lower(sfm.name)=:serviceName 16 | """ ,nativeQuery = true) 17 | Optional findNativeLastNodeForModuleAndService(String moduleName, String serviceName); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/config/McpKeepAliveConfig.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.config; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import io.modelcontextprotocol.server.transport.WebFluxSseServerTransportProvider; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.scheduling.annotation.EnableScheduling; 9 | import org.springframework.scheduling.annotation.Scheduled; 10 | import reactor.core.Disposable; 11 | import reactor.core.publisher.Flux; 12 | 13 | import java.time.Duration; 14 | 15 | @Configuration 16 | @EnableScheduling // важно! 17 | public class McpKeepAliveConfig { 18 | 19 | @Bean 20 | public Disposable heartbeatLoop(WebFluxSseServerTransportProvider provider) { 21 | return Flux.interval(Duration.ofSeconds(40)) 22 | .flatMap(t -> provider.sendHeartbeat()) 23 | .subscribe(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/data/CallMethodRepositoryDTO.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.data; 2 | 3 | import java.time.Instant; 4 | import java.time.OffsetDateTime; 5 | import java.util.UUID; 6 | 7 | public interface CallMethodRepositoryDTO { 8 | 9 | UUID getMessageId(); 10 | 11 | UUID getTraceId(); 12 | 13 | UUID getSpanId(); 14 | 15 | UUID getCallIdParent(); 16 | 17 | String getModuleName(); 18 | 19 | String getServiceName(); 20 | 21 | String getClassName(); 22 | 23 | String getMethodName(); 24 | 25 | String getOperationType(); 26 | 27 | Instant getCallTimeDateStart(); 28 | 29 | Instant getCallTimeDateEnd(); 30 | 31 | Boolean getInPointFlag(); 32 | 33 | Double getCallTimeDelta(); 34 | 35 | Integer getCodeResponse(); 36 | 37 | String getDataInsert(); 38 | 39 | String getLibraryVersion(); 40 | 41 | String getArgs(); 42 | 43 | String getErrorCallMessage(); 44 | 45 | String getMethodReturn(); 46 | 47 | String getServiceCallId(); 48 | 49 | } -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/data/CallMethodDTO.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.data; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | 6 | import java.time.OffsetDateTime; 7 | import java.util.List; 8 | import java.util.UUID; 9 | 10 | @Getter 11 | @Builder 12 | public class CallMethodDTO { 13 | private UUID id; 14 | private UUID traceId; 15 | private UUID spanId; 16 | private String className; 17 | private String methodName; 18 | private UUID callIdParent; 19 | private String args; 20 | private OffsetDateTime callTimeDateStart; 21 | private OffsetDateTime callTimeDateEnd; 22 | private String methodReturn; 23 | private String errorCallMessage; 24 | private Long inPointId; 25 | private String moduleName; 26 | private String serviceName; 27 | private Boolean inPointFlag; 28 | private Double callTimeDelta; 29 | private String operationType; 30 | private Integer codeResponse; 31 | private List callMethodSqlList; 32 | private List callMethodRests; 33 | private List callMethodQueue; 34 | private String libraryVersion; 35 | private CallMethodRestDTO restCallMethod; 36 | } -------------------------------------------------------------------------------- /HELP.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ### Reference Documentation 4 | For further reference, please consider the following sections: 5 | 6 | * [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) 7 | * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/3.4.5/maven-plugin) 8 | * [Create an OCI image](https://docs.spring.io/spring-boot/3.4.5/maven-plugin/build-image.html) 9 | * [Spring Web](https://docs.spring.io/spring-boot/3.4.5/reference/web/servlet.html) 10 | 11 | ### Guides 12 | The following guides illustrate how to use some features concretely: 13 | 14 | * [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/) 15 | * [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/) 16 | * [Building REST services with Spring](https://spring.io/guides/tutorials/rest/) 17 | 18 | ### Maven Parent overrides 19 | 20 | Due to Maven's design, elements are inherited from the parent POM to the project POM. 21 | While most of the inheritance is fine, it also inherits unwanted elements like `` and `` from the parent. 22 | To prevent this, the project POM contains empty overrides for these elements. 23 | If you manually switch to a different parent and actually want the inheritance, you need to remove those overrides. 24 | 25 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: ${POSTGRES_URL:jdbc:postgresql://37.27.0.220:5432/data-bitdive} 4 | username: ${POSTGRES_USER:citizix_user} 5 | password: ${POSTGRES_PASS:S3cret} 6 | driver-class-name: org.postgresql.Driver 7 | ai: 8 | mcp: 9 | server: 10 | request-timeout: 180 11 | enabled: true 12 | type: ASYNC 13 | name: bitdive-mcp # как будет называться сервер в списке Cursor 14 | version: 1.0.0 15 | instructions: | 16 | Этот сервер предоставляет инструменты для работы с системой мониторинга BitDive. 17 | # SSE-конечные точки (по умолчанию /sse и /mcp/message) 18 | sse-endpoint: /sse 19 | sse-message-endpoint: /mcp/message 20 | 21 | 22 | app: 23 | key-secret: 24 | token-secret: ${TOKEN_SECRET:2IC9hzeMOIPBCyv3Ew5BDCcRPBI8nwuSFQ/jXlQZ+1A=} 25 | vault: 26 | url: ${VAULT_URL:https://sandbox.bitdive.io/vault} 27 | login: ${VAULT_LOGIN:username} 28 | password: ${VAULT_PASSWORD:password123} 29 | certificationForDataBase: 30 | commonName: ${VAULT_CERTIFICATION_DB_COMMON_NAME:citizix_user} 31 | altNames: ${VAULT_CERTIFICATION_DB_ALT_NAME:localhost} 32 | ttl: ${VAULT_CERTIFICATION_DB_TTL:24h} 33 | server: 34 | netty: 35 | idle-timeout: -1 # отключить IdleTimeoutHandler 36 | port: 8089 -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/HierarchyMethodUIDto.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | import java.time.OffsetDateTime; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.UUID; 11 | 12 | @Builder 13 | @Getter 14 | @Setter 15 | public class HierarchyMethodUIDto { 16 | private UUID messageId; 17 | private String className; 18 | private String methodName; 19 | private UUID spanId; 20 | private UUID traceId; 21 | private String args; 22 | private OffsetDateTime callTimeDateStart; 23 | private OffsetDateTime callTimeDateEnd; 24 | private Double callTimeDelta; 25 | private String methodReturn; 26 | private String errorCallMessage; 27 | private String moduleName; 28 | private String serviceName; 29 | private Boolean inPointFlag; 30 | private Integer codeResponse; 31 | private String url; 32 | private String operationType; 33 | private List sqlCalls = new ArrayList<>(); 34 | private List restCalls = new ArrayList<>(); 35 | private List queueCalls = new ArrayList<>(); 36 | private List childCalls = new ArrayList<>(); 37 | private String libraryVersion; 38 | private RestCall restCallMethod; 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/component/PiiMaskClientComponent.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.component; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.http.HttpEntity; 6 | import org.springframework.http.HttpHeaders; 7 | import org.springframework.http.MediaType; 8 | import org.springframework.stereotype.Component; 9 | import org.springframework.web.client.RestTemplate; 10 | 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | @Component 15 | public class PiiMaskClientComponent { 16 | private final RestTemplate restTemplate = new RestTemplate(); 17 | 18 | @Value("${pii.service.url:http://localhost:8888/mask}") 19 | private String maskEndpoint; 20 | 21 | public String maskText(String text) { 22 | // Заголовки 23 | HttpHeaders headers = new HttpHeaders(); 24 | headers.setContentType(MediaType.APPLICATION_JSON); 25 | 26 | // Тело запроса 27 | MaskRequest request = new MaskRequest(text); 28 | HttpEntity entity = new HttpEntity<>(request, headers); 29 | 30 | var maskResponse= restTemplate.postForObject(maskEndpoint, entity, MaskResponse.class); 31 | // Отправка POST и получение MaskResponse 32 | return maskResponse.maskedText; 33 | } 34 | 35 | record MaskRequest (String text) {} 36 | 37 | static class MaskResponse { 38 | @JsonProperty("masked_text") 39 | private String maskedText; 40 | 41 | private Map> entities; 42 | } 43 | } 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/entity/ModuleCallAnalytics.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.entity; 2 | 3 | import jakarta.persistence.Column; 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.Id; 6 | import jakarta.persistence.Table; 7 | import lombok.Getter; 8 | import org.hibernate.annotations.JdbcTypeCode; 9 | import org.hibernate.type.SqlTypes; 10 | 11 | import java.time.OffsetDateTime; 12 | import java.util.UUID; 13 | 14 | @Entity 15 | @Table(name = "module_call_analytics") 16 | @Getter 17 | public class ModuleCallAnalytics { 18 | @Id 19 | @JdbcTypeCode(SqlTypes.CHAR) 20 | private UUID id; 21 | private Integer idReport; 22 | private String moduleName; 23 | private Integer errorCount; 24 | private Integer callCountWeb; 25 | private Double avgCallTimeWeb; 26 | private Integer callCountScheduler; 27 | private Double avgCallTimeScheduler; 28 | private Integer sqlCallCount; 29 | private Double avgSqlCallTime; 30 | private Integer sqlErrorCount; 31 | private Integer restCallCount; 32 | private Double avgRestCallTime; 33 | private Integer restErrorCount; 34 | @Column(name = "count_2xx") 35 | private Integer count2xx; 36 | @Column(name = "count_3xx") 37 | private Integer count3xx; 38 | @Column(name = "count_4xx") 39 | private Integer count4xx; 40 | @Column(name = "count_5xx") 41 | private Integer count5xx; 42 | 43 | private Integer queueSendCount; 44 | private Double avgQueueSendTime; 45 | private Integer queueSendErrorCount; 46 | private Integer queueConsumerCount; 47 | private Double queueConsumerAvgCallTime; 48 | private Integer queueConsumerErrorCount; 49 | 50 | 51 | private OffsetDateTime analysisTimestamp; 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/entity/ServiceCallAnalytics.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.entity; 2 | 3 | import jakarta.persistence.Column; 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.Id; 6 | import jakarta.persistence.Table; 7 | import lombok.Getter; 8 | import org.hibernate.annotations.JdbcTypeCode; 9 | import org.hibernate.type.SqlTypes; 10 | 11 | import java.time.OffsetDateTime; 12 | import java.util.UUID; 13 | 14 | @Entity 15 | @Table(name = "service_call_analytics") 16 | @Getter 17 | public class ServiceCallAnalytics { 18 | @Id 19 | @JdbcTypeCode(SqlTypes.CHAR) 20 | private UUID id; 21 | 22 | private Integer idReport; 23 | private String moduleName; 24 | private String serviceName; 25 | private Integer errorCount; 26 | private Integer callCountWeb; 27 | private Double avgCallTimeWeb; 28 | private Integer callCountScheduler; 29 | private Double avgCallTimeScheduler; 30 | private Integer sqlCallCount; 31 | private Double avgSqlCallTime; 32 | private Integer sqlErrorCount; 33 | private Integer restCallCount; 34 | private Double avgRestCallTime; 35 | private Integer restErrorCount; 36 | @Column(name = "count_2xx") 37 | private Integer count2xx; 38 | @Column(name = "count_3xx") 39 | private Integer count3xx; 40 | @Column(name = "count_4xx") 41 | private Integer count4xx; 42 | @Column(name = "count_5xx") 43 | private Integer count5xx; 44 | 45 | private Integer queueSendCount; 46 | private Double avgQueueSendTime; 47 | private Integer queueSendErrorCount; 48 | private Integer queueConsumerCount; 49 | private Double queueConsumerAvgCallTime; 50 | private Integer queueConsumerErrorCount; 51 | 52 | private OffsetDateTime analysisTimestamp; 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/entity/ClassCallAnalytics.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.entity; 2 | 3 | import jakarta.persistence.Column; 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.Id; 6 | import jakarta.persistence.Table; 7 | import lombok.Getter; 8 | import org.hibernate.annotations.JdbcTypeCode; 9 | import org.hibernate.type.SqlTypes; 10 | 11 | import java.time.OffsetDateTime; 12 | import java.util.UUID; 13 | 14 | @Entity 15 | @Table(name = "class_call_analytics") 16 | @Getter 17 | public class ClassCallAnalytics { 18 | @Id 19 | @JdbcTypeCode(SqlTypes.CHAR) 20 | private UUID id; 21 | 22 | private Integer idReport; 23 | private String moduleName; 24 | private String serviceName; 25 | private String className; 26 | private Integer errorCount; 27 | private Integer callCountWeb; 28 | private Double avgCallTimeWeb; 29 | private Integer callCountScheduler; 30 | private Double avgCallTimeScheduler; 31 | private Integer sqlCallCount; 32 | private Double avgSqlCallTime; 33 | private Integer sqlErrorCount; 34 | private Integer restCallCount; 35 | private Double avgRestCallTime; 36 | private Integer restErrorCount; 37 | @Column(name = "count_2xx") 38 | private Integer count2xx; 39 | @Column(name = "count_3xx") 40 | private Integer count3xx; 41 | @Column(name = "count_4xx") 42 | private Integer count4xx; 43 | @Column(name = "count_5xx") 44 | private Integer count5xx; 45 | 46 | private Integer queueSendCount; 47 | private Double avgQueueSendTime; 48 | private Integer queueSendErrorCount; 49 | private Integer queueConsumerCount; 50 | private Double queueConsumerAvgCallTime; 51 | private Integer queueConsumerErrorCount; 52 | 53 | 54 | private OffsetDateTime analysisTimestamp; 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/entity/InPointCallAnalytics.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.entity; 2 | 3 | import jakarta.persistence.Column; 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.Id; 6 | import jakarta.persistence.Table; 7 | import lombok.Getter; 8 | import org.hibernate.annotations.JdbcTypeCode; 9 | import org.hibernate.type.SqlTypes; 10 | 11 | import java.time.OffsetDateTime; 12 | import java.util.UUID; 13 | 14 | @Entity 15 | @Table(name = "in_point_call_analytics") 16 | @Getter 17 | public class InPointCallAnalytics { 18 | @Id 19 | @JdbcTypeCode(SqlTypes.CHAR) 20 | private UUID id; 21 | 22 | private Integer idReport; 23 | private String moduleName; 24 | private String serviceName; 25 | private String className; 26 | private String methodName; 27 | private Integer errorCount; 28 | private Integer callCountWeb; 29 | private Double avgCallTimeWeb; 30 | private Integer callCountScheduler; 31 | private Double avgCallTimeScheduler; 32 | private Integer sqlCallCount; 33 | private Double avgSqlCallTime; 34 | private Integer sqlErrorCount; 35 | private Integer restCallCount; 36 | private Double avgRestCallTime; 37 | private Integer restErrorCount; 38 | @Column(name = "count_2xx") 39 | private Integer count2xx; 40 | @Column(name = "count_3xx") 41 | private Integer count3xx; 42 | @Column(name = "count_4xx") 43 | private Integer count4xx; 44 | @Column(name = "count_5xx") 45 | private Integer count5xx; 46 | 47 | private Integer queueSendCount; 48 | private Double avgQueueSendTime; 49 | private Integer queueSendErrorCount; 50 | private Integer queueConsumerCount; 51 | private Double queueConsumerAvgCallTime; 52 | private Integer queueConsumerErrorCount; 53 | 54 | 55 | private OffsetDateTime analysisTimestamp; 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/heap_map/InPointAnalyticsDTO.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.heap_map; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | 7 | import java.time.OffsetDateTime; 8 | import java.util.List; 9 | 10 | @Getter 11 | @Setter 12 | @NoArgsConstructor 13 | public class InPointAnalyticsDTO extends AnalyticsBaseDTO { 14 | private String inPointName; 15 | 16 | public InPointAnalyticsDTO( 17 | String inPointName, 18 | OffsetDateTime timestamp, 19 | Integer errorCount, 20 | Integer callCountWeb, 21 | Double avgCallTimeWeb, 22 | Integer callCountScheduler, 23 | Double avgCallTimeScheduler, 24 | Integer sqlCallCount, 25 | Double avgSqlCallTime, 26 | Integer sqlErrorCount, 27 | Integer restCallCount, 28 | Double avgRestCallTime, 29 | Integer restErrorCount, 30 | Integer count2xx, 31 | Integer count3xx, 32 | Integer count4xx, 33 | Integer count5xx, 34 | Integer queueSendCount , 35 | Double avgQueueSendTime , 36 | Integer queueSendErrorCount , 37 | Integer queueConsumerCount , 38 | Double queueConsumerAvgCallTime , 39 | Integer queueConsumerErrorCount 40 | ) { 41 | 42 | super(timestamp, errorCount, callCountWeb, avgCallTimeWeb, callCountScheduler, 43 | avgCallTimeScheduler, sqlCallCount, avgSqlCallTime, sqlErrorCount, 44 | restCallCount, avgRestCallTime, restErrorCount, count2xx, count3xx, 45 | count4xx, count5xx,queueSendCount ,avgQueueSendTime ,queueSendErrorCount , 46 | queueConsumerCount ,queueConsumerAvgCallTime ,queueConsumerErrorCount); 47 | 48 | this.inPointName = inPointName; 49 | } 50 | } -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/utils/FinalConvertObject.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.utils; 2 | 3 | import com.fasterxml.jackson.core.type.TypeReference; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 6 | import io.bitdive.mcpserver.dto.hierarchy_method.HierarchyMethodUIDto; 7 | import io.bitdive.mcpserver.dto.hierarchy_method.heap_map.ModuleAnalyticsDTO; 8 | 9 | import java.time.format.DateTimeFormatter; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | public class FinalConvertObject { 14 | private static final ObjectMapper objectMapper = new ObjectMapper(); 15 | private static final DateTimeFormatter fmt = DateTimeFormatter.ISO_OFFSET_DATE_TIME; 16 | 17 | static { 18 | objectMapper.registerModule(new JavaTimeModule()); 19 | } 20 | 21 | public static String getStringObjectString(Object objectsVal) { 22 | try { 23 | return objectMapper.writeValueAsString(objectsVal); 24 | } catch (Exception e) { 25 | throw new RuntimeException(e); 26 | } 27 | } 28 | 29 | public static Map getStringObject(Object objectsVal) { 30 | try { 31 | String inPointJson = objectMapper.writeValueAsString(objectsVal); 32 | return objectMapper.readValue(inPointJson, new TypeReference>() { 33 | }); 34 | } catch (Exception e) { 35 | throw new RuntimeException(e); 36 | } 37 | } 38 | 39 | public static List> getListOfMaps(Object objectsVal) { 40 | try { 41 | String json = objectMapper.writeValueAsString(objectsVal); 42 | return objectMapper.readValue( 43 | json, 44 | new TypeReference>>() {} 45 | ); 46 | } catch (Exception e) { 47 | throw new RuntimeException(e); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/service/LastCallTools.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.service; 2 | 3 | import io.bitdive.mcpserver.component.LastCallComponent; 4 | import io.bitdive.mcpserver.config.securety.ApiKeyComponent; 5 | import io.bitdive.mcpserver.config.securety.ApiKeyReactiveAuthManager; 6 | import io.bitdive.mcpserver.config.securety.dto.CurrentUser; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.ai.tool.annotation.Tool; 10 | import org.springframework.ai.tool.annotation.ToolParam; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | import static io.bitdive.mcpserver.utils.FinalConvertObject.getListOfMaps; 17 | 18 | @Service 19 | @RequiredArgsConstructor 20 | @Slf4j 21 | public class LastCallTools { 22 | 23 | private final LastCallComponent lastCallComponent; 24 | private final ApiKeyComponent apiKeyComponent; 25 | 26 | @Tool(name = "getLastCallService", description = "returns a list of recent runs with id trace") 27 | public List> lastCallService( 28 | @ToolParam(description = "module name") String moduleName, 29 | @ToolParam(description = "service name") String serviceName, 30 | @ToolParam(description = "API key for mcp bitDive access") String apiKey) { 31 | log.info("Getting last call service for module: {} and service: {}", moduleName, serviceName); 32 | 33 | try { 34 | var currentUser= verificationApiKey(apiKey); 35 | return getListOfMaps(lastCallComponent.lastCallService(moduleName, serviceName,currentUser)); 36 | }catch (Exception e) { 37 | throw new RuntimeException("Failed to get returns a list of recent runs with id trace" + moduleName + "." + serviceName , e); 38 | } 39 | 40 | } 41 | 42 | private CurrentUser verificationApiKey(String apiKey) throws Exception { 43 | return apiKeyComponent.decryptApiKey(apiKey); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/heap_map/ClassAnalyticsDTO.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.heap_map; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | 7 | import java.time.OffsetDateTime; 8 | import java.util.List; 9 | 10 | @Getter 11 | @Setter 12 | @NoArgsConstructor 13 | public class ClassAnalyticsDTO extends AnalyticsBaseDTO { 14 | private String className; 15 | private List inPoints; 16 | 17 | public ClassAnalyticsDTO( 18 | String className, 19 | OffsetDateTime timestamp, 20 | Integer errorCount, 21 | Integer callCountWeb, 22 | Double avgCallTimeWeb, 23 | Integer callCountScheduler, 24 | Double avgCallTimeScheduler, 25 | Integer sqlCallCount, 26 | Double avgSqlCallTime, 27 | Integer sqlErrorCount, 28 | Integer restCallCount, 29 | Double avgRestCallTime, 30 | Integer restErrorCount, 31 | Integer count2xx, 32 | Integer count3xx, 33 | Integer count4xx, 34 | Integer count5xx, 35 | Integer queueSendCount , 36 | Double avgQueueSendTime , 37 | Integer queueSendErrorCount , 38 | Integer queueConsumerCount , 39 | Double queueConsumerAvgCallTime , 40 | Integer queueConsumerErrorCount, 41 | List inPoints 42 | ) { 43 | super(timestamp, errorCount, callCountWeb, avgCallTimeWeb, callCountScheduler, 44 | avgCallTimeScheduler, sqlCallCount, avgSqlCallTime, sqlErrorCount, 45 | restCallCount, avgRestCallTime, restErrorCount, count2xx, count3xx, 46 | count4xx, count5xx,queueSendCount ,avgQueueSendTime ,queueSendErrorCount , 47 | queueConsumerCount ,queueConsumerAvgCallTime ,queueConsumerErrorCount); 48 | this.className = className; 49 | this.inPoints = inPoints; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/heap_map/ModuleAnalyticsDTO.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.heap_map; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | 7 | import java.time.OffsetDateTime; 8 | import java.util.List; 9 | 10 | @Getter 11 | @Setter 12 | @NoArgsConstructor 13 | public class ModuleAnalyticsDTO extends AnalyticsBaseDTO { 14 | private String moduleName; 15 | private List services; 16 | 17 | public ModuleAnalyticsDTO( 18 | String moduleName, 19 | OffsetDateTime timestamp, 20 | Integer errorCount, 21 | Integer callCountWeb, 22 | Double avgCallTimeWeb, 23 | Integer callCountScheduler, 24 | Double avgCallTimeScheduler, 25 | Integer sqlCallCount, 26 | Double avgSqlCallTime, 27 | Integer sqlErrorCount, 28 | Integer restCallCount, 29 | Double avgRestCallTime, 30 | Integer restErrorCount, 31 | Integer count2xx, 32 | Integer count3xx, 33 | Integer count4xx, 34 | Integer count5xx, 35 | Integer queueSendCount , 36 | Double avgQueueSendTime , 37 | Integer queueSendErrorCount , 38 | Integer queueConsumerCount , 39 | Double queueConsumerAvgCallTime , 40 | Integer queueConsumerErrorCount, 41 | List services 42 | ) { 43 | super(timestamp, errorCount, callCountWeb, avgCallTimeWeb, callCountScheduler, 44 | avgCallTimeScheduler, sqlCallCount, avgSqlCallTime, sqlErrorCount, 45 | restCallCount, avgRestCallTime, restErrorCount, count2xx, count3xx, 46 | count4xx, count5xx,queueSendCount ,avgQueueSendTime ,queueSendErrorCount , 47 | queueConsumerCount ,queueConsumerAvgCallTime ,queueConsumerErrorCount); 48 | this.moduleName = moduleName; 49 | this.services = services; 50 | } 51 | } -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/heap_map/ServiceAnalyticsDTO.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.heap_map; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | 7 | import java.time.OffsetDateTime; 8 | import java.util.List; 9 | 10 | @Getter 11 | @Setter 12 | @NoArgsConstructor 13 | public class ServiceAnalyticsDTO extends AnalyticsBaseDTO { 14 | private String serviceName; 15 | private List classes; 16 | 17 | public ServiceAnalyticsDTO( 18 | String serviceName, 19 | OffsetDateTime timestamp, 20 | Integer errorCount, 21 | Integer callCountWeb, 22 | Double avgCallTimeWeb, 23 | Integer callCountScheduler, 24 | Double avgCallTimeScheduler, 25 | Integer sqlCallCount, 26 | Double avgSqlCallTime, 27 | Integer sqlErrorCount, 28 | Integer restCallCount, 29 | Double avgRestCallTime, 30 | Integer restErrorCount, 31 | Integer count2xx, 32 | Integer count3xx, 33 | Integer count4xx, 34 | Integer count5xx, 35 | Integer queueSendCount , 36 | Double avgQueueSendTime , 37 | Integer queueSendErrorCount , 38 | Integer queueConsumerCount , 39 | Double queueConsumerAvgCallTime , 40 | Integer queueConsumerErrorCount, 41 | List classes 42 | ) { 43 | super(timestamp, errorCount, callCountWeb, avgCallTimeWeb, callCountScheduler, 44 | avgCallTimeScheduler, sqlCallCount, avgSqlCallTime, sqlErrorCount, 45 | restCallCount, avgRestCallTime, restErrorCount, count2xx, count3xx, 46 | count4xx, count5xx,queueSendCount ,avgQueueSendTime ,queueSendErrorCount , 47 | queueConsumerCount ,queueConsumerAvgCallTime ,queueConsumerErrorCount); 48 | this.serviceName = serviceName; 49 | this.classes = classes; 50 | } 51 | } -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/component/LastCallComponent.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.component; 2 | 3 | import io.bitdive.mcpserver.config.securety.dto.CurrentUser; 4 | import io.bitdive.mcpserver.db.repository.CallMethodRepository; 5 | import io.bitdive.mcpserver.db.repository.ServiceNodeForModuleRepository; 6 | import io.bitdive.mcpserver.dto.last_call.LastCallReturn; 7 | import lombok.RequiredArgsConstructor; 8 | import org.springframework.stereotype.Component; 9 | 10 | import java.time.ZoneOffset; 11 | import java.util.List; 12 | 13 | import static io.bitdive.mcpserver.utils.UserViewModule.isViewForModule; 14 | 15 | 16 | @Component 17 | @RequiredArgsConstructor 18 | public class LastCallComponent { 19 | private final ServiceNodeForModuleRepository serviceNodeForModuleRepository; 20 | private final CallMethodRepository callMethodRepository; 21 | 22 | public List lastCallService(String moduleName , String serviceName , CurrentUser currentUser) { 23 | 24 | if (!isViewForModule(currentUser,moduleName)) return List.of(); 25 | 26 | var lastNodeIdOptional = serviceNodeForModuleRepository.findNativeLastNodeForModuleAndService(moduleName.toLowerCase(), serviceName.toLowerCase()); 27 | if (lastNodeIdOptional.isPresent()) { 28 | var lastCall = callMethodRepository.lastCallModuleAndService(lastNodeIdOptional.get().getId()); 29 | return lastCall.stream().map(lastCallModuleAndServiceDTO -> 30 | new LastCallReturn( 31 | lastCallModuleAndServiceDTO.getMessageId(), 32 | lastCallModuleAndServiceDTO.getModuleName(), 33 | lastCallModuleAndServiceDTO.getServiceName(), 34 | lastCallModuleAndServiceDTO.getClassName(), 35 | lastCallModuleAndServiceDTO.getMethodName(), 36 | lastCallModuleAndServiceDTO.getCallDateTime().atOffset(ZoneOffset.UTC) 37 | ) 38 | ).toList(); 39 | 40 | } 41 | return List.of(); 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/repository/CallMethodSqlRepository.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.repository; 2 | 3 | import io.bitdive.mcpserver.db.entity.CallMethodSql; 4 | import io.bitdive.mcpserver.dto.hierarchy_method.data.CallMethodSqlRepositoryDTO; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.Query; 7 | import org.springframework.data.repository.query.Param; 8 | 9 | import java.time.OffsetDateTime; 10 | import java.util.List; 11 | import java.util.UUID; 12 | 13 | public interface CallMethodSqlRepository extends JpaRepository { 14 | 15 | @Query(value = """ 16 | SELECT 17 | id, spanid, traceid, messageid, 18 | decrypt_decompress(cmsv.callmethodsqlparam, :keyDecrypt) as callMethodSqlParam, 19 | decrypt_decompress(cmsv.sql, :keyDecrypt) as callMethodSqlText, 20 | calltimedatestart as callTimeDateStart, 21 | calltimedateend as callTimeDateEnd, 22 | calltimedelta, 23 | decrypt_decompress(cmsv.errorcallmessage, :keyDecrypt) as errorCallMessage, 24 | callidmessage, libraryversion 25 | FROM call_method_sql_full_data_view cmsv 26 | WHERE cmsv.spanid in (:traceAndSpanIdList) and cast(cmsv.calltimedatestart as timestamp with time zone) between :dateStart and :dateEnd 27 | """, 28 | nativeQuery = true) 29 | List findSqlSpanIdAndTraceIdAndCallIdParent( 30 | @Param("traceAndSpanIdList") List traceAndSpanIdList, 31 | @Param("keyDecrypt") String keyDecrypt, 32 | @Param("dateStart") OffsetDateTime dateStart, 33 | @Param("dateEnd")OffsetDateTime dateEnd 34 | ); 35 | 36 | 37 | @Query(value = "SELECT " + 38 | " *, " + 39 | " calltimedatestart as callTimeDateStart, " + 40 | " calltimedateend as callTimeDateEnd " + 41 | "FROM call_method_sql_full_data_view cmsv " + 42 | "WHERE cmsv.spanid in (:traceAndSpanIdList)", 43 | nativeQuery = true) 44 | List findBySpanIdAndTraceIdAndCallIdParent( 45 | @Param("traceAndSpanIdList") List traceAndSpanIdList 46 | ); 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/repository/CallMethodQueueSendRepository.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.repository; 2 | 3 | import io.bitdive.mcpserver.db.entity.CallMethodQueueSendEntity; 4 | import io.bitdive.mcpserver.dto.hierarchy_method.data.CallMethodQueueSendRepositoryDTO; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.Query; 7 | import org.springframework.data.repository.query.Param; 8 | import org.springframework.stereotype.Repository; 9 | 10 | import java.time.OffsetDateTime; 11 | import java.util.List; 12 | import java.util.UUID; 13 | 14 | @Repository 15 | public interface CallMethodQueueSendRepository extends JpaRepository { 16 | 17 | @Query(value = """ 18 | SELECT 19 | cmqs.message_id as messageId, 20 | cmqs.span_id as spanId , cmqs.trace_id as traceId, cmqs.call_id_message as callIdMessage, 21 | decrypt_decompress(cmqs.message_body, :keyDecrypt) as messageBody, 22 | to_char(cmqs.call_time_date_start, 'YYYY-MM-DD"T"HH24:MI:SS.USOF') as callTimeDateStart, 23 | to_char(cmqs.call_time_date_end, 'YYYY-MM-DD"T"HH24:MI:SS.USOF') as callTimeDateEnd, 24 | cmqs.call_time_delta as callTimeDelta, 25 | cmqser.queue_server as queueServer, 26 | cmqt.name as topicName, 27 | lv.library_version as libraryVersion, 28 | decrypt_decompress(cmqs.error_call, :keyDecrypt) as errorCall, 29 | cmqs.is_error as isError 30 | FROM call_method_queue_send cmqs 31 | left join public.library_version lv on cmqs.library_version_id = lv.id 32 | left join call_method_queue_server cmqser on cmqser.id=cmqs.queue_server_id 33 | left join call_method_queue_topic cmqt on cmqt.id=cmqs.queue_topic_id 34 | WHERE cmqs.span_id in (:traceAndSpanIdList) and cmqs.call_time_date_start between :dateStart and :dateEnd 35 | """,nativeQuery = true) 36 | List findSqlSpanIdAndTraceIdAndCallIdParent( 37 | @Param("traceAndSpanIdList") List traceAndSpanIdList, 38 | @Param("keyDecrypt") String keyDecrypt, 39 | @Param("dateStart") OffsetDateTime dateStart, 40 | @Param("dateEnd")OffsetDateTime dateEnd 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/repository/CallMethodRestRepository.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.repository; 2 | 3 | import io.bitdive.mcpserver.db.entity.CallMethodRest; 4 | import io.bitdive.mcpserver.dto.hierarchy_method.data.CallMethodRestRepositoryDTO; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.Query; 7 | import org.springframework.data.repository.query.Param; 8 | 9 | import java.time.OffsetDateTime; 10 | import java.util.List; 11 | import java.util.UUID; 12 | 13 | public interface CallMethodRestRepository extends JpaRepository { 14 | @Query(value = """ 15 | SELECT id, 16 | spanid, 17 | traceid, 18 | messageid, 19 | callidmessage, 20 | datestart as datestart, 21 | dateend as dateend, 22 | calltimedelta, 23 | url, 24 | methodname, 25 | decrypt_decompress(headers , :keyDecrypt) as headers, 26 | decrypt_decompress(body , :keyDecrypt) as body, 27 | statuscode, 28 | decrypt_decompress(responseheaders , :keyDecrypt) as responseHeaders, 29 | decrypt_decompress(responsebody , :keyDecrypt) as responseBody, 30 | decrypt_decompress(errorcall , :keyDecrypt) as errorcall, 31 | libraryversion, 32 | service_call_id as serviceCallId 33 | FROM call_method_rest_full_data_view cmv 34 | WHERE cmv.spanid in (:traceAndSpanIdList) and cast(cmv.datestart as timestamp with time zone) between :dateStart and :dateEnd 35 | """ 36 | , nativeQuery = true) 37 | List findSpanIdAndTraceIdAndCallIdParent( 38 | @Param("traceAndSpanIdList") List traceAndSpanIdList, 39 | @Param("keyDecrypt") String keyDecrypt, 40 | @Param("dateStart") OffsetDateTime dateStart, 41 | @Param("dateEnd")OffsetDateTime dateEnd 42 | ); 43 | 44 | @Query(value = "SELECT " + 45 | " * "+ 46 | "FROM call_method_rest_full_data_view cmv " + 47 | "WHERE cmv.spanid in (:traceAndSpanIdList)", nativeQuery = true) 48 | List findTraceAndSpanIdAndCallIdMessage( 49 | @Param("traceAndSpanIdList") List traceAndSpanIdList 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/component/MonitoringHeapMapComponent.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.component; 2 | 3 | import io.bitdive.mcpserver.config.securety.dto.CurrentUser; 4 | import io.bitdive.mcpserver.dto.hierarchy_method.heap_map.ModuleAnalyticsDTO; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | import static io.bitdive.mcpserver.utils.FinalConvertObject.getListOfMaps; 12 | 13 | @Component 14 | @RequiredArgsConstructor 15 | public class MonitoringHeapMapComponent { 16 | 17 | private final AnalyticsService analyticsService; 18 | 19 | public List getAllModuleAnalytics(CurrentUser currentUser) { 20 | return analyticsService.getAnalyticsData(1,currentUser); 21 | } 22 | 23 | public List> getCurrentHeapMap(CurrentUser currentUser) { 24 | return getListOfMaps(getAllModuleAnalytics(currentUser)); 25 | } 26 | 27 | public List> getCurrentHeapMap(String moduleName, CurrentUser currentUser) { 28 | var allModuleAnalytics = getAllModuleAnalytics(currentUser); 29 | var listRet = allModuleAnalytics.stream() 30 | .filter(moduleAnalyticsDTO -> moduleAnalyticsDTO.getModuleName().equalsIgnoreCase(moduleName)) 31 | .toList(); 32 | 33 | return getListOfMaps(listRet); 34 | } 35 | 36 | public List> getCurrentHeapMap(String moduleName, String serviceName, CurrentUser currentUser) { 37 | var allModuleAnalytics = getAllModuleAnalytics(currentUser); 38 | var listRet = allModuleAnalytics.stream() 39 | .filter(moduleAnalyticsDTO -> moduleAnalyticsDTO.getModuleName().equalsIgnoreCase(moduleName)) 40 | .flatMap(moduleAnalyticsDTO -> moduleAnalyticsDTO.getServices().stream()) 41 | .filter(moduleAnalyticsDTO -> moduleAnalyticsDTO.getServiceName().equalsIgnoreCase(serviceName)) 42 | .toList(); 43 | return getListOfMaps(listRet); 44 | } 45 | 46 | public List> getCurrentHeapMap(String moduleName, String serviceName, String className, CurrentUser currentUser) { 47 | var allModuleAnalytics = getAllModuleAnalytics(currentUser); 48 | var listRet = allModuleAnalytics.stream() 49 | .filter(moduleAnalyticsDTO -> moduleAnalyticsDTO.getModuleName().equalsIgnoreCase(moduleName)) 50 | .flatMap(moduleAnalyticsDTO -> moduleAnalyticsDTO.getServices().stream()) 51 | .filter(moduleAnalyticsDTO -> moduleAnalyticsDTO.getServiceName().equalsIgnoreCase(serviceName)) 52 | .flatMap(moduleAnalyticsDTO -> moduleAnalyticsDTO.getClasses().stream()) 53 | .filter(moduleAnalyticsDTO -> moduleAnalyticsDTO.getClassName().equalsIgnoreCase(className)) 54 | .toList(); 55 | return getListOfMaps(listRet); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/dto/hierarchy_method/heap_map/AnalyticsBaseDTO.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.dto.hierarchy_method.heap_map; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | 7 | import java.time.OffsetDateTime; 8 | import java.util.List; 9 | 10 | @Getter 11 | @Setter 12 | @NoArgsConstructor 13 | public class AnalyticsBaseDTO { 14 | private OffsetDateTime timestamp; 15 | 16 | // Metrics 17 | private Integer errorCount; 18 | private Integer callCountWeb; 19 | private Double avgCallTimeWeb; 20 | private Integer callCountScheduler; 21 | private Double avgCallTimeScheduler; 22 | private Integer sqlCallCount; 23 | private Double avgSqlCallTime; 24 | private Integer sqlErrorCount; 25 | private Integer restCallCount; 26 | private Double avgRestCallTime; 27 | private Integer restErrorCount; 28 | private Integer count2xx; 29 | private Integer count3xx; 30 | private Integer count4xx; 31 | private Integer count5xx; 32 | private Integer queueSendCount; 33 | private Double avgQueueSendTime; 34 | private Integer queueSendErrorCount; 35 | private Integer queueConsumerCount; 36 | private Double queueConsumerAvgCallTime; 37 | private Integer queueConsumerErrorCount; 38 | 39 | private Integer totalErrorCount; 40 | 41 | public AnalyticsBaseDTO(OffsetDateTime timestamp, Integer errorCount, Integer callCountWeb, Double avgCallTimeWeb, 42 | Integer callCountScheduler, Double avgCallTimeScheduler, Integer sqlCallCount, Double avgSqlCallTime, 43 | Integer sqlErrorCount, Integer restCallCount, Double avgRestCallTime, Integer restErrorCount, 44 | Integer count2xx, Integer count3xx, Integer count4xx, Integer count5xx,Integer queueSendCount , 45 | Double avgQueueSendTime ,Integer queueSendErrorCount ,Integer queueConsumerCount ,Double queueConsumerAvgCallTime , 46 | Integer queueConsumerErrorCount) { 47 | this.timestamp = timestamp; 48 | this.errorCount = errorCount; 49 | this.callCountWeb = callCountWeb; 50 | this.avgCallTimeWeb = avgCallTimeWeb; 51 | this.callCountScheduler = callCountScheduler; 52 | this.avgCallTimeScheduler = avgCallTimeScheduler; 53 | this.sqlCallCount = sqlCallCount; 54 | this.avgSqlCallTime = avgSqlCallTime; 55 | this.sqlErrorCount = sqlErrorCount; 56 | this.restCallCount = restCallCount; 57 | this.avgRestCallTime = avgRestCallTime; 58 | this.restErrorCount = restErrorCount; 59 | this.count2xx = count2xx; 60 | this.count3xx = count3xx; 61 | this.count4xx = count4xx; 62 | this.count5xx = count5xx; 63 | this.queueSendCount=queueSendCount; 64 | this.avgQueueSendTime=avgQueueSendTime; 65 | this.queueSendErrorCount=queueSendErrorCount; 66 | this.queueConsumerCount=queueConsumerCount; 67 | this.queueConsumerAvgCallTime=queueConsumerAvgCallTime; 68 | this.queueConsumerErrorCount=queueConsumerErrorCount; 69 | this.totalErrorCount = errorCount+ restErrorCount +sqlErrorCount+queueSendErrorCount+queueConsumerErrorCount; 70 | } 71 | } -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/component/MonitoringComponent.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.component; 2 | 3 | import com.fasterxml.jackson.core.type.TypeReference; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 6 | import io.bitdive.mcpserver.config.securety.dto.CurrentUser; 7 | import io.bitdive.mcpserver.dto.hierarchy_method.HierarchyMethodUIDto; 8 | import io.bitdive.mcpserver.dto.hierarchy_method.data.CallMethodRepositoryDTO; 9 | import io.bitdive.mcpserver.utils.FinalConvertObject; 10 | import io.bitdive.mcpserver.utils.HierarchySearcher; 11 | import lombok.RequiredArgsConstructor; 12 | import org.springframework.ai.tool.annotation.ToolParam; 13 | import org.springframework.stereotype.Component; 14 | import java.time.OffsetDateTime; 15 | import java.time.ZoneOffset; 16 | import java.time.format.DateTimeFormatter; 17 | import java.util.*; 18 | import java.util.stream.Collectors; 19 | 20 | import static io.bitdive.mcpserver.utils.FinalConvertObject.getStringObject; 21 | import static io.bitdive.mcpserver.utils.FinalConvertObject.getStringObjectString; 22 | 23 | @Component 24 | @RequiredArgsConstructor 25 | public class MonitoringComponent { 26 | 27 | private final InPointProvider inPointProvider; 28 | private final PiiMaskClientComponent piiMaskClientComponent; 29 | private static final ObjectMapper objectMapper = new ObjectMapper(); 30 | private static final DateTimeFormatter fmt = DateTimeFormatter.ISO_OFFSET_DATE_TIME; 31 | 32 | static { 33 | objectMapper.registerModule(new JavaTimeModule()); 34 | } 35 | 36 | public Map findTraceForMethodBetweenTime(String className, String methodName, OffsetDateTime beginDate, OffsetDateTime endDate, CurrentUser currentUser) { 37 | String beginUtc = beginDate.withOffsetSameInstant(ZoneOffset.UTC).format(fmt); 38 | String endUtc = endDate.withOffsetSameInstant(ZoneOffset.UTC).format(fmt); 39 | 40 | return inPointProvider.findClassAndMethodBetweenDate(className, methodName, beginUtc, endUtc) 41 | .stream() 42 | .map(callMethodRepositoryDTO -> inPointProvider.getInPointOneCall(callMethodRepositoryDTO.getInPointMessageId(),currentUser)) 43 | .collect(Collectors.toMap( 44 | dto -> dto.getMessageId().toString(), 45 | FinalConvertObject::getStringObject 46 | ) 47 | ); 48 | } 49 | 50 | public Map findTraceForMethod(String callId, String className, String methodName, CurrentUser currentUser) { 51 | var inPointOneCall = inPointProvider.getInPointOneCall(UUID.fromString(callId),currentUser); 52 | 53 | return HierarchySearcher.findInHierarchy(inPointOneCall, className, methodName) 54 | .map(FinalConvertObject::getStringObject) 55 | .orElseThrow(() -> new RuntimeException("inPointOneCall not found")); 56 | } 57 | 58 | public String findTraceAll(String callId , CurrentUser currentUser) { 59 | var inPointOneCall = inPointProvider.getInPointOneCall(UUID.fromString(callId),currentUser); 60 | return getStringObjectString(inPointOneCall) /*piiMaskClientComponent.maskText()*/; 61 | } 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/service/TraceTools.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.service; 2 | 3 | import io.bitdive.mcpserver.component.MonitoringComponent; 4 | import io.bitdive.mcpserver.config.securety.ApiKeyAuthenticationToken; 5 | import io.bitdive.mcpserver.config.securety.ApiKeyComponent; 6 | import io.bitdive.mcpserver.config.securety.ApiKeyReactiveAuthManager; 7 | import io.bitdive.mcpserver.config.securety.dto.CurrentUser; 8 | import lombok.RequiredArgsConstructor; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.ai.tool.annotation.Tool; 11 | import org.springframework.ai.tool.annotation.ToolParam; 12 | //import org.springframework.security.core.Authentication; 13 | import org.springframework.stereotype.Service; 14 | 15 | import java.time.OffsetDateTime; 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | @Service 20 | @RequiredArgsConstructor 21 | @Slf4j 22 | public class TraceTools { 23 | 24 | private final MonitoringComponent monitoringComponent; 25 | private final ApiKeyComponent apiKeyComponent; 26 | 27 | @Tool(name = "findTraceAll", description = "Returns the full call trace for the specified call ID") 28 | public String findTraceAll( 29 | @ToolParam(description = "Call ID") String callId, 30 | @ToolParam(description = "API key for mcp bitDive access") String apiKey) { 31 | try { 32 | var currentUser= verificationApiKey(apiKey); 33 | return monitoringComponent.findTraceAll(callId,currentUser); 34 | } catch (Exception e) { 35 | throw new RuntimeException("Failed to get trace for callId: " + callId, e); 36 | } 37 | } 38 | 39 | @Tool(name = "findTraceForMethod", description = "Returns the call trace for a specific method within the given call ID") 40 | public Map findTraceForMethod( 41 | @ToolParam(description = "Call ID") String callId, 42 | @ToolParam(description = "Fully qualified class name") String className, 43 | @ToolParam(description = "Method name") String methodName, 44 | @ToolParam(description = "API key for mcp bitDive access") String apiKey) { 45 | 46 | try { 47 | var currentUser= verificationApiKey(apiKey); 48 | return monitoringComponent.findTraceForMethod(callId, className, methodName,currentUser); 49 | } catch (Exception e) { 50 | throw new RuntimeException("Failed to get trace for method " + className + "." + methodName + " in call " + callId, e); 51 | } 52 | } 53 | 54 | @Tool(name = "findTraceForMethodBetweenTime", 55 | description = "Returns the call trace for the specified class and method between the given start and end timestamps") 56 | public Map findTraceForMethodBetweenTime( 57 | @ToolParam(description = "Fully qualified class name") String className, 58 | @ToolParam(description = "Method name") String methodName, 59 | @ToolParam(description = "Start timestamp in ISO-8601 format including the client's current local timezone offset") OffsetDateTime beginDate, 60 | @ToolParam(description = "End timestamp in ISO-8601 format including the client's current local timezone offset") OffsetDateTime endDate, 61 | @ToolParam(description = "API key for mcp bitDive access") String apiKey) { 62 | 63 | try { 64 | var currentUser= verificationApiKey(apiKey); 65 | return monitoringComponent.findTraceForMethodBetweenTime(className, methodName, beginDate, endDate,currentUser); 66 | } catch (Exception e) { 67 | throw new RuntimeException("Failed to get trace for method " + className + "." + methodName + " between " + beginDate + " and " + endDate, e); 68 | } 69 | } 70 | 71 | private CurrentUser verificationApiKey(String apiKey) throws Exception { 72 | return apiKeyComponent.decryptApiKey(apiKey); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/service/HeadMapTools.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.service; 2 | 3 | import io.bitdive.mcpserver.component.MonitoringHeapMapComponent; 4 | import io.bitdive.mcpserver.config.securety.ApiKeyComponent; 5 | import io.bitdive.mcpserver.config.securety.ApiKeyReactiveAuthManager; 6 | import io.bitdive.mcpserver.config.securety.dto.CurrentUser; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.ai.tool.annotation.Tool; 10 | import org.springframework.ai.tool.annotation.ToolParam; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | @Service 17 | @RequiredArgsConstructor 18 | @Slf4j 19 | public class HeadMapTools { 20 | 21 | private final MonitoringHeapMapComponent monitoringHeapMapComponent; 22 | private final ApiKeyComponent apiKeyComponent; 23 | 24 | @Tool(name = "getCurrentHeapMapAllSystem", description = "Returns system performance metrics all system") 25 | public List> getCurrentHeapMap(@ToolParam(description = "API key for mcp bitDive access") String apiKey) { 26 | log.info("Getting current heap map for all system"); 27 | 28 | try { 29 | var currentUser = verificationApiKey(apiKey); 30 | return monitoringHeapMapComponent.getCurrentHeapMap(currentUser); 31 | } catch (Exception e) { 32 | throw new RuntimeException("Failed to get current heap map for all system", e); 33 | } 34 | } 35 | 36 | @Tool(name = "getCurrentHeapMapForModule", description = "Returns system performance metrics for module") 37 | public List> getCurrentHeapMapForModule( 38 | @ToolParam(description = "module name") String moduleName, 39 | @ToolParam(description = "API key for mcp bitDive access") String apiKey) { 40 | log.info("Getting current heap map for module: {}", moduleName); 41 | try { 42 | var currentUser = verificationApiKey(apiKey); 43 | return monitoringHeapMapComponent.getCurrentHeapMap(moduleName,currentUser); 44 | } catch (Exception e) { 45 | throw new RuntimeException(String.format("Failed to get current heap map for module '%s'", moduleName),e); 46 | } 47 | } 48 | 49 | @Tool(name = "getCurrentHeapMapForModuleAndForService", description = "Returns system performance metrics for module and for service") 50 | public List> getCurrentHeapMapForModuleAndForService( 51 | @ToolParam(description = "module name") String moduleName, 52 | @ToolParam(description = "service name") String serviceName, 53 | @ToolParam(description = "API key for mcp bitDive access") String apiKey) { 54 | log.info("Getting current heap map for module: {} and service: {}", moduleName, serviceName); 55 | try { 56 | var currentUser = verificationApiKey(apiKey); 57 | return monitoringHeapMapComponent.getCurrentHeapMap(moduleName, serviceName,currentUser); 58 | } catch (Exception e) { 59 | throw new RuntimeException( 60 | String.format("Failed to get current heap map for module '%s' and service '%s'", moduleName, serviceName), 61 | e 62 | ); 63 | } 64 | 65 | } 66 | 67 | @Tool(name = "getCurrentHeapMapForModuleAndForServiceClass", description = "Returns system performance metrics for module and for service and class") 68 | public List> getCurrentHeapMapForModuleAndForServiceClass( 69 | @ToolParam(description = "module name") String moduleName, 70 | @ToolParam(description = "service name") String serviceName, 71 | @ToolParam(description = "class name") String className, 72 | @ToolParam(description = "API key for mcp bitDive access") String apiKey) { 73 | log.info("Getting current heap map for module: {}, service: {}, class: {}", moduleName, serviceName, className); 74 | try { 75 | var currentUser = verificationApiKey(apiKey); 76 | return monitoringHeapMapComponent.getCurrentHeapMap(moduleName, serviceName, className,currentUser); 77 | } catch (Exception e) { 78 | throw new RuntimeException( 79 | String.format("Failed to get current heap map for module '%s', service '%s', class '%s'", 80 | moduleName, serviceName, className), 81 | e 82 | ); 83 | } 84 | } 85 | 86 | 87 | private CurrentUser verificationApiKey(String apiKey) throws Exception { 88 | return apiKeyComponent.decryptApiKey(apiKey); 89 | } 90 | 91 | 92 | } 93 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 3.2.0 10 | 11 | 12 | io.bitDive 13 | mcp-server 14 | 0.0.1-SNAPSHOT 15 | mcp-server 16 | mcp-server 17 | 18 | 17 19 | 1.0.0 20 | 21 | 22 | 23 | 24 | 25 | org.springframework.ai 26 | spring-ai-bom 27 | ${spring-ai.version} 28 | pom 29 | import 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | io.modelcontextprotocol.sdk 38 | mcp-spring-webflux 39 | 0.10.1-SNAPSHOT 40 | 41 | 42 | com.knuddels 43 | jtokkit 44 | 1.1.0 45 | 46 | 47 | 48 | 49 | com.nimbusds 50 | nimbus-jose-jwt 51 | 9.37.3 52 | 53 | 54 | 55 | 56 | org.springframework.ai 57 | spring-ai-starter-mcp-server-webflux 58 | 59 | 60 | 61 | commons-codec 62 | commons-codec 63 | 64 | 65 | com.bettercloud 66 | vault-java-driver 67 | 5.1.0 68 | 69 | 70 | 71 | org.bouncycastle 72 | bcprov-jdk18on 73 | 1.79 74 | 75 | 76 | org.bouncycastle 77 | bcpkix-jdk18on 78 | 1.79 79 | 80 | 81 | 82 | org.postgresql 83 | postgresql 84 | 42.7.2 85 | 86 | 87 | 88 | org.springframework.boot 89 | spring-boot-starter-data-jpa 90 | 91 | 92 | 93 | 94 | org.projectlombok 95 | lombok 96 | true 97 | 98 | 99 | com.fasterxml.jackson.core 100 | jackson-databind 101 | 102 | 103 | org.slf4j 104 | slf4j-api 105 | 106 | 107 | org.apache.commons 108 | commons-lang3 109 | 110 | 111 | com.fasterxml.jackson.datatype 112 | jackson-datatype-jsr310 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | org.springframework.boot 122 | spring-boot-maven-plugin 123 | 124 | 125 | 126 | org.projectlombok 127 | lombok 128 | 129 | 130 | 131 | 132 | 133 | 134 | org.apache.maven.plugins 135 | maven-resources-plugin 136 | 137 | 138 | copy-jar 139 | package 140 | 141 | copy-resources 142 | 143 | 144 | ../docker/docker-file-mcp-server 145 | 146 | 147 | ${project.build.directory} 148 | 149 | *.jar 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/utils/HierarchyUtils.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.utils; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.knuddels.jtokkit.Encodings; 5 | import com.knuddels.jtokkit.api.Encoding; 6 | import com.knuddels.jtokkit.api.EncodingRegistry; 7 | import com.knuddels.jtokkit.api.EncodingType; 8 | import com.knuddels.jtokkit.api.IntArrayList; 9 | import io.bitdive.mcpserver.dto.hierarchy_method.HierarchyMethodUIDto; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Comparator; 13 | import java.util.LinkedList; 14 | import java.util.List; 15 | import java.util.Optional; 16 | import java.util.Queue; 17 | 18 | import static io.bitdive.mcpserver.utils.FinalConvertObject.getStringObjectString; 19 | 20 | public class HierarchyUtils { 21 | private static final int MAX_CHILDREN = 30; 22 | private static final int MAX_TOKENS = 40000; // предел токенов 23 | private static final double TRIM_RATIO = 0.7; // оставляем 70% 24 | 25 | private static final int MAX_TRIM_PASSES = 15; 26 | 27 | private static final EncodingRegistry registry = Encodings.newDefaultEncodingRegistry(); 28 | private static final Encoding encoding = registry.getEncoding(EncodingType.CL100K_BASE); 29 | 30 | /** 31 | * Универсальный метод: сначала проверяет лимит токенов, затем: 32 | * 1) обрезает childCalls до MAX_CHILDREN 33 | * 2) снова проверяет лимит токенов 34 | * 3) если всё ещё превышает, начинает укорачивать поля args/methodReturn 35 | */ 36 | public static void enforceLimits(HierarchyMethodUIDto root) { 37 | if (root == null) { 38 | return; 39 | } 40 | int totalTokens = countTokens(root); 41 | if (totalTokens <= MAX_TOKENS) { 42 | return; 43 | } 44 | 45 | trimChildCallsIterative(root); 46 | totalTokens = countTokens(root); 47 | if (totalTokens <= MAX_TOKENS) { 48 | return; 49 | } 50 | 51 | trimToTokenLimit(root); 52 | } 53 | 54 | private static void trimChildCallsIterative(HierarchyMethodUIDto root) { 55 | if (root == null) { 56 | return; 57 | } 58 | Queue queue = new LinkedList<>(); 59 | queue.add(root); 60 | while (!queue.isEmpty()) { 61 | HierarchyMethodUIDto current = queue.poll(); 62 | List children = current.getChildCalls(); 63 | if (children.size() > MAX_CHILDREN) { 64 | children.subList(MAX_CHILDREN, children.size()).clear(); 65 | } 66 | queue.addAll(children); 67 | } 68 | } 69 | 70 | private static int countTokens(String prompt) { 71 | if (prompt == null || prompt.isEmpty()) { 72 | return 0; 73 | } 74 | IntArrayList tokenIds = encoding.encode(prompt); 75 | return tokenIds.size(); 76 | } 77 | 78 | private static int countTokens(HierarchyMethodUIDto node) { 79 | if (node == null) { 80 | return 0; 81 | } 82 | try { 83 | String json = getStringObjectString(node); 84 | return countTokens(json); 85 | } catch (Exception e) { 86 | return 0; 87 | } 88 | } 89 | 90 | 91 | private static void trimToTokenLimit(HierarchyMethodUIDto root) { 92 | if (root == null) { 93 | return; 94 | } 95 | int total = countTokens(root); 96 | int passes = 0; 97 | while (total > MAX_TOKENS && passes < MAX_TRIM_PASSES) { 98 | Optional largest = findLargestField(root); 99 | if (largest.isEmpty()) { 100 | break; 101 | } 102 | FieldRef ref = largest.get(); 103 | String original = ref.getValue(); 104 | int newLen = Math.max(1, (int) Math.ceil(original.length() * TRIM_RATIO)); 105 | ref.setValue(original.substring(0, newLen)); 106 | total = countTokens(root); 107 | 108 | passes++; 109 | } 110 | } 111 | 112 | private static Optional findLargestField(HierarchyMethodUIDto root) { 113 | return collectFields(root).stream() 114 | .max(Comparator.comparingInt(f -> f.getValue().length())); 115 | } 116 | 117 | private static List collectFields(HierarchyMethodUIDto node) { 118 | List fields = new ArrayList<>(); 119 | collect(node, fields); 120 | return fields; 121 | } 122 | 123 | private static void collect(HierarchyMethodUIDto node, List out) { 124 | if (node == null) { 125 | return; 126 | } 127 | if (node.getArgs() != null && !node.getArgs().isEmpty()) { 128 | out.add(new FieldRef(node, true)); 129 | } 130 | if (node.getMethodReturn() != null && !node.getMethodReturn().isEmpty()) { 131 | out.add(new FieldRef(node, false)); 132 | } 133 | for (HierarchyMethodUIDto child : node.getChildCalls()) { 134 | collect(child, out); 135 | } 136 | } 137 | 138 | private static class FieldRef { 139 | private final HierarchyMethodUIDto node; 140 | private final boolean isArgs; 141 | 142 | FieldRef(HierarchyMethodUIDto node, boolean isArgs) { 143 | this.node = node; 144 | this.isArgs = isArgs; 145 | } 146 | 147 | String getValue() { 148 | return isArgs ? node.getArgs() : node.getMethodReturn(); 149 | } 150 | 151 | void setValue(String newVal) { 152 | if (isArgs) { 153 | node.setArgs(newVal); 154 | } else { 155 | node.setMethodReturn(newVal); 156 | } 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/component/InPointProvider.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.component; 2 | 3 | import io.bitdive.mcpserver.config.securety.dto.CurrentUser; 4 | import io.bitdive.mcpserver.config.vault.VaultService; 5 | import io.bitdive.mcpserver.db.repository.CallMethodQueueSendRepository; 6 | import io.bitdive.mcpserver.db.repository.CallMethodRepository; 7 | import io.bitdive.mcpserver.db.repository.CallMethodRestRepository; 8 | import io.bitdive.mcpserver.db.repository.CallMethodSqlRepository; 9 | import io.bitdive.mcpserver.dto.hierarchy_method.HierarchyMethodUIDto; 10 | import io.bitdive.mcpserver.dto.hierarchy_method.data.*; 11 | import io.bitdive.mcpserver.utils.CallMethodConverter; 12 | import io.bitdive.mcpserver.utils.HierarchyUtils; 13 | import io.bitdive.mcpserver.utils.UtilsCovert; 14 | import lombok.RequiredArgsConstructor; 15 | import org.springframework.stereotype.Component; 16 | import org.apache.commons.lang3.ObjectUtils; 17 | 18 | import java.time.OffsetDateTime; 19 | import java.time.ZoneOffset; 20 | import java.util.*; 21 | import java.util.stream.Collectors; 22 | 23 | import static io.bitdive.mcpserver.utils.UserViewModule.isViewForModule; 24 | 25 | @Component 26 | @RequiredArgsConstructor 27 | public class InPointProvider { 28 | 29 | private final VaultService vaultService ; 30 | private final CallMethodRepository callMethodRepository; 31 | private final CallMethodRestRepository callMethodRestRepository; 32 | private final CallMethodSqlRepository callMethodSqlRepository; 33 | private final CallMethodQueueSendRepository callMethodQueueSendRepository; 34 | 35 | public List findClassAndMethodBetweenDate(String className , String methodName , String dateCallStart, String dateCallEnd){ 36 | return callMethodRepository.findClassAndMethodBetweenDate(className, methodName, dateCallStart, dateCallEnd); 37 | } 38 | 39 | public HierarchyMethodUIDto getInPointOneCall(UUID callId, CurrentUser currentUser) { 40 | 41 | List callList = null; 42 | 43 | long startTime = System.currentTimeMillis(); 44 | if (vaultService.isSLLConnected()) 45 | callList = callMethodRepository.findTreeCall(callId, vaultService.decryptKeyForData()); 46 | else 47 | callList = callMethodRepository.findTreeCall(callId); 48 | 49 | callList=callList.stream() 50 | .filter(callMethodRepositoryDTO -> isViewForModule(currentUser,callMethodRepositoryDTO.getModuleName())) 51 | .toList(); 52 | 53 | long endTime = System.currentTimeMillis(); 54 | System.out.println("Call method time: " + (endTime - startTime)); 55 | 56 | List callsRest = new ArrayList<>(); 57 | 58 | var spanIdList = callList.stream() 59 | .map(CallMethodRepositoryDTO::getSpanId) 60 | .distinct() 61 | .toList(); 62 | 63 | var dataStart = callList.stream() 64 | .map(callMethodRepositoryDTO -> callMethodRepositoryDTO.getCallTimeDateStart().atOffset(ZoneOffset.UTC)) 65 | .min((OffsetDateTime::compareTo)) 66 | .orElse(OffsetDateTime.now()); 67 | 68 | var dataEnd = callList.stream() 69 | .map(callMethodRepositoryDTO -> callMethodRepositoryDTO.getCallTimeDateEnd().atOffset(ZoneOffset.UTC)) 70 | .max((OffsetDateTime::compareTo)) 71 | .orElse(OffsetDateTime.now()); 72 | 73 | if (vaultService.isSLLConnected()) 74 | callsRest = callMethodRestRepository.findSpanIdAndTraceIdAndCallIdParent(spanIdList, vaultService.decryptKeyForData(), dataStart, dataEnd); 75 | else 76 | callsRest = callMethodRestRepository.findTraceAndSpanIdAndCallIdMessage(spanIdList); 77 | 78 | List callsSQL = new ArrayList<>(); 79 | 80 | if (vaultService.isSLLConnected()) 81 | callsSQL = callMethodSqlRepository.findSqlSpanIdAndTraceIdAndCallIdParent(spanIdList, vaultService.decryptKeyForData(), dataStart, dataEnd); 82 | else 83 | callsSQL = callMethodSqlRepository.findBySpanIdAndTraceIdAndCallIdParent(spanIdList); 84 | 85 | 86 | List callsQueue = 87 | callMethodQueueSendRepository.findSqlSpanIdAndTraceIdAndCallIdParent(spanIdList, vaultService.decryptKeyForData(), dataStart, dataEnd); 88 | 89 | List finalCallsRest = callsRest; 90 | List finalCallsSQL = callsSQL; 91 | 92 | var listServiceCallId = callList.stream().map(CallMethodRepositoryDTO::getServiceCallId).filter(Objects::nonNull).toList(); 93 | 94 | var CallMethods = callList.stream().map(callMethod -> { 95 | 96 | var callsRestList = finalCallsRest.stream() 97 | .filter(callMethodRestRest -> { 98 | 99 | if (ObjectUtils.isEmpty(callMethodRestRest.getServiceCallId()) || 100 | 101 | (ObjectUtils.isNotEmpty(callMethodRestRest.getServiceCallId()) && !listServiceCallId.contains(callMethodRestRest.getServiceCallId())) 102 | 103 | ) { 104 | return callMethodRestRest.getCallIdMessage().equals(callMethod.getMessageId()); 105 | } 106 | return false; 107 | }) 108 | .toList(); 109 | 110 | var callsRestServiceList = finalCallsRest.stream() 111 | .filter(callMethodRestRest -> { 112 | if (!ObjectUtils.isEmpty(callMethodRestRest.getServiceCallId())) { 113 | return callMethodRestRest.getServiceCallId().equals(callMethod.getServiceCallId()); 114 | } 115 | return false; 116 | }) 117 | .toList(); 118 | 119 | var callsSQLList = finalCallsSQL.stream() 120 | .filter(callMethodSql -> callMethodSql.getCallIdMessage().equals(callMethod.getMessageId())) 121 | .toList(); 122 | 123 | var CallQueueLsit = callsQueue.stream() 124 | .filter(callMethodSql -> callMethodSql.getCallIdMessage().equals(callMethod.getMessageId())) 125 | .toList(); 126 | 127 | 128 | return CallMethodConverter.toDTO(callMethod, callsSQLList, callsRestList, callsRestServiceList, CallQueueLsit); 129 | }).toList(); 130 | 131 | var hierarchyMethodUIDto= UtilsCovert.buildDependencyTree(CallMethods); 132 | HierarchyUtils.enforceLimits(hierarchyMethodUIDto); 133 | return hierarchyMethodUIDto; 134 | 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | <# : batch portion 2 | @REM ---------------------------------------------------------------------------- 3 | @REM Licensed to the Apache Software Foundation (ASF) under one 4 | @REM or more contributor license agreements. See the NOTICE file 5 | @REM distributed with this work for additional information 6 | @REM regarding copyright ownership. The ASF licenses this file 7 | @REM to you under the Apache License, Version 2.0 (the 8 | @REM "License"); you may not use this file except in compliance 9 | @REM with the License. You may obtain a copy of the License at 10 | @REM 11 | @REM http://www.apache.org/licenses/LICENSE-2.0 12 | @REM 13 | @REM Unless required by applicable law or agreed to in writing, 14 | @REM software distributed under the License is distributed on an 15 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | @REM KIND, either express or implied. See the License for the 17 | @REM specific language governing permissions and limitations 18 | @REM under the License. 19 | @REM ---------------------------------------------------------------------------- 20 | 21 | @REM ---------------------------------------------------------------------------- 22 | @REM Apache Maven Wrapper startup batch script, version 3.3.2 23 | @REM 24 | @REM Optional ENV vars 25 | @REM MVNW_REPOURL - repo url base for downloading maven distribution 26 | @REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven 27 | @REM MVNW_VERBOSE - true: enable verbose log; others: silence the output 28 | @REM ---------------------------------------------------------------------------- 29 | 30 | @IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) 31 | @SET __MVNW_CMD__= 32 | @SET __MVNW_ERROR__= 33 | @SET __MVNW_PSMODULEP_SAVE=%PSModulePath% 34 | @SET PSModulePath= 35 | @FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( 36 | IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) 37 | ) 38 | @SET PSModulePath=%__MVNW_PSMODULEP_SAVE% 39 | @SET __MVNW_PSMODULEP_SAVE= 40 | @SET __MVNW_ARG0_NAME__= 41 | @SET MVNW_USERNAME= 42 | @SET MVNW_PASSWORD= 43 | @IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) 44 | @echo Cannot start maven from wrapper >&2 && exit /b 1 45 | @GOTO :EOF 46 | : end batch / begin powershell #> 47 | 48 | $ErrorActionPreference = "Stop" 49 | if ($env:MVNW_VERBOSE -eq "true") { 50 | $VerbosePreference = "Continue" 51 | } 52 | 53 | # calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties 54 | $distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl 55 | if (!$distributionUrl) { 56 | Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" 57 | } 58 | 59 | switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { 60 | "maven-mvnd-*" { 61 | $USE_MVND = $true 62 | $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" 63 | $MVN_CMD = "mvnd.cmd" 64 | break 65 | } 66 | default { 67 | $USE_MVND = $false 68 | $MVN_CMD = $script -replace '^mvnw','mvn' 69 | break 70 | } 71 | } 72 | 73 | # apply MVNW_REPOURL and calculate MAVEN_HOME 74 | # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ 75 | if ($env:MVNW_REPOURL) { 76 | $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } 77 | $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" 78 | } 79 | $distributionUrlName = $distributionUrl -replace '^.*/','' 80 | $distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' 81 | $MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" 82 | if ($env:MAVEN_USER_HOME) { 83 | $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" 84 | } 85 | $MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' 86 | $MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" 87 | 88 | if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { 89 | Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" 90 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 91 | exit $? 92 | } 93 | 94 | if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { 95 | Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" 96 | } 97 | 98 | # prepare tmp dir 99 | $TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile 100 | $TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" 101 | $TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null 102 | trap { 103 | if ($TMP_DOWNLOAD_DIR.Exists) { 104 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 105 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 106 | } 107 | } 108 | 109 | New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null 110 | 111 | # Download and Install Apache Maven 112 | Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." 113 | Write-Verbose "Downloading from: $distributionUrl" 114 | Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" 115 | 116 | $webclient = New-Object System.Net.WebClient 117 | if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { 118 | $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) 119 | } 120 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 121 | $webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null 122 | 123 | # If specified, validate the SHA-256 sum of the Maven distribution zip file 124 | $distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum 125 | if ($distributionSha256Sum) { 126 | if ($USE_MVND) { 127 | Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." 128 | } 129 | Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash 130 | if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { 131 | Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." 132 | } 133 | } 134 | 135 | # unzip and move 136 | Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null 137 | Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null 138 | try { 139 | Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null 140 | } catch { 141 | if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { 142 | Write-Error "fail to move MAVEN_HOME" 143 | } 144 | } finally { 145 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 146 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 147 | } 148 | 149 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 150 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/utils/CallMethodConverter.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.utils; 2 | 3 | import io.bitdive.mcpserver.dto.hierarchy_method.data.*; 4 | 5 | import java.time.OffsetDateTime; 6 | import java.time.ZoneOffset; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.Optional; 10 | 11 | public class CallMethodConverter { 12 | 13 | public static CallMethodDTO toDTO(CallMethodRepositoryDTO callMethod, 14 | List callMethodSqlList, 15 | List callMethodRests, 16 | List callsRestServiceList, 17 | List callQueueSendList 18 | ) { 19 | if (callMethod == null) { 20 | return null; 21 | } 22 | 23 | List callMethodRestDTOS = convertCallMethodRestDTOS(callMethodRests); 24 | CallMethodRestDTO callServiceRestDTOS = convertCallMethodRestDTOS(callsRestServiceList).stream().findFirst().orElse(null); 25 | List callMethodSqlDTOS = convertCallMethodSqlDTOS(callMethodSqlList); 26 | List callMethodQueueDTOS = convertCallMethodQueueDTOS(callQueueSendList); 27 | 28 | return CallMethodDTO.builder() 29 | .id(callMethod.getMessageId()) 30 | .traceId(callMethod.getTraceId()) 31 | .spanId(callMethod.getSpanId()) 32 | .className(callMethod.getClassName()) 33 | .methodName(callMethod.getMethodName()) 34 | .callIdParent(callMethod.getCallIdParent()) 35 | .args(callMethod.getArgs()) 36 | .callTimeDateStart(callMethod.getCallTimeDateStart().atOffset(ZoneOffset.UTC)) 37 | .callTimeDateEnd(callMethod.getCallTimeDateEnd().atOffset(ZoneOffset.UTC)) 38 | .methodReturn(callMethod.getMethodReturn()) 39 | .errorCallMessage(callMethod.getErrorCallMessage()) 40 | .moduleName(callMethod.getModuleName()) 41 | .serviceName(callMethod.getServiceName()) 42 | .inPointFlag(callMethod.getInPointFlag()) 43 | .callTimeDelta(callMethod.getCallTimeDelta()) 44 | .operationType(callMethod.getOperationType()) 45 | .codeResponse(callMethod.getCodeResponse()) 46 | .callMethodSqlList(callMethodSqlDTOS) 47 | .callMethodRests(callMethodRestDTOS) 48 | .callMethodQueue(callMethodQueueDTOS) 49 | .restCallMethod(callServiceRestDTOS) 50 | .libraryVersion(callMethod.getLibraryVersion()) 51 | .build(); 52 | } 53 | 54 | public static List convertCallMethodQueueDTOS(List callMethodQueueList) { 55 | List callMethodQueueDTOS = new ArrayList<>(); 56 | if (Optional.ofNullable(callMethodQueueList).isPresent()) { 57 | callMethodQueueDTOS = callMethodQueueList.stream() 58 | .map(callMethodQueueSendDTO -> 59 | CallMethodQueueSendDTO.builder() 60 | .messageId(callMethodQueueSendDTO.getMessageId()) 61 | .spanId(callMethodQueueSendDTO.getSpanId()) 62 | .traceId(callMethodQueueSendDTO.getTraceId()) 63 | .callIdMessage(callMethodQueueSendDTO.getCallIdMessage()) 64 | .messageBody(callMethodQueueSendDTO.getMessageBody()) 65 | .callTimeDateStart(OffsetDateTime.parse(callMethodQueueSendDTO.getCallTimeDateStart())) 66 | .callTimeDateEnd(OffsetDateTime.parse(callMethodQueueSendDTO.getCallTimeDateEnd())) 67 | .callTimeDelta(callMethodQueueSendDTO.getCallTimeDelta()) 68 | .queueServer(callMethodQueueSendDTO.getQueueServer()) 69 | .topicName(callMethodQueueSendDTO.getTopicName()) 70 | .libraryVersion(callMethodQueueSendDTO.getLibraryVersion()) 71 | .errorCall(callMethodQueueSendDTO.getErrorCall()) 72 | .isError(callMethodQueueSendDTO.getIsError()) 73 | .build() 74 | ).toList(); 75 | } 76 | return callMethodQueueDTOS; 77 | } 78 | 79 | private static List convertCallMethodSqlDTOS(List callMethodSqlList) { 80 | List callMethodSqlDTOS = new ArrayList<>(); 81 | if (Optional.ofNullable(callMethodSqlList).isPresent()) { 82 | callMethodSqlDTOS = callMethodSqlList.stream() 83 | .map(callMethodSqlRepositoryDTO -> 84 | CallMethodSqlDTO.builder() 85 | .id(callMethodSqlRepositoryDTO.getId()) 86 | .spanId(callMethodSqlRepositoryDTO.getSpanId()) 87 | .traceId(callMethodSqlRepositoryDTO.getTraceId()) 88 | .messageId(callMethodSqlRepositoryDTO.getMessageId()) 89 | .callTimeDateStart(OffsetDateTime.parse(callMethodSqlRepositoryDTO.getCallTimeDateStart())) 90 | .callTimeDateEnd(OffsetDateTime.parse(callMethodSqlRepositoryDTO.getCallTimeDateEnd())) 91 | .callTimeDelta(callMethodSqlRepositoryDTO.getCallTimeDelta()) 92 | .callIdMessage(callMethodSqlRepositoryDTO.getCallIdMessage()) 93 | .libraryVersion(callMethodSqlRepositoryDTO.getLibraryVersion()) 94 | .callMethodSqlParam(callMethodSqlRepositoryDTO.getCallMethodSqlParam()) 95 | .callMethodSqlText(callMethodSqlRepositoryDTO.getCallMethodSqlText()) 96 | .errorCallMessage(callMethodSqlRepositoryDTO.getErrorCallMessage()) 97 | .build() 98 | ).toList(); 99 | } 100 | return callMethodSqlDTOS; 101 | } 102 | 103 | private static List convertCallMethodRestDTOS(List callMethodRests) { 104 | List callMethodRestDTOS = new ArrayList<>(); 105 | if (Optional.ofNullable(callMethodRests).isPresent()) { 106 | callMethodRestDTOS = callMethodRests.stream() 107 | .map(callMethodRestRepositoryDTO -> 108 | CallMethodRestDTO.builder() 109 | .traceId(callMethodRestRepositoryDTO.getTraceId()) 110 | .messageId(callMethodRestRepositoryDTO.getMessageId()) 111 | .callIdMessage(callMethodRestRepositoryDTO.getCallIdMessage()) 112 | .dateStart(OffsetDateTime.parse(callMethodRestRepositoryDTO.getDateStart())) 113 | .dateEnd(OffsetDateTime.parse(callMethodRestRepositoryDTO.getDateEnd())) 114 | .callTimeDelta(callMethodRestRepositoryDTO.getCallTimeDelta()) 115 | .uri(callMethodRestRepositoryDTO.getUrl()) 116 | .methodId(callMethodRestRepositoryDTO.getMethodName()) 117 | .headers(callMethodRestRepositoryDTO.getHeaders()) 118 | .body(callMethodRestRepositoryDTO.getBody()) 119 | .statusCode(callMethodRestRepositoryDTO.getStatusCode()) 120 | .responseHeaders(callMethodRestRepositoryDTO.getResponseHeaders()) 121 | .responseBody(callMethodRestRepositoryDTO.getResponseBody()) 122 | .errorCall(callMethodRestRepositoryDTO.getErrorCall()) 123 | .libraryVersion(callMethodRestRepositoryDTO.getLibraryVersion()) 124 | .build()) 125 | .toList(); 126 | } 127 | return callMethodRestDTOS; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Apache Maven Wrapper startup batch script, version 3.3.2 23 | # 24 | # Optional ENV vars 25 | # ----------------- 26 | # JAVA_HOME - location of a JDK home dir, required when download maven via java source 27 | # MVNW_REPOURL - repo url base for downloading maven distribution 28 | # MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven 29 | # MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output 30 | # ---------------------------------------------------------------------------- 31 | 32 | set -euf 33 | [ "${MVNW_VERBOSE-}" != debug ] || set -x 34 | 35 | # OS specific support. 36 | native_path() { printf %s\\n "$1"; } 37 | case "$(uname)" in 38 | CYGWIN* | MINGW*) 39 | [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" 40 | native_path() { cygpath --path --windows "$1"; } 41 | ;; 42 | esac 43 | 44 | # set JAVACMD and JAVACCMD 45 | set_java_home() { 46 | # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched 47 | if [ -n "${JAVA_HOME-}" ]; then 48 | if [ -x "$JAVA_HOME/jre/sh/java" ]; then 49 | # IBM's JDK on AIX uses strange locations for the executables 50 | JAVACMD="$JAVA_HOME/jre/sh/java" 51 | JAVACCMD="$JAVA_HOME/jre/sh/javac" 52 | else 53 | JAVACMD="$JAVA_HOME/bin/java" 54 | JAVACCMD="$JAVA_HOME/bin/javac" 55 | 56 | if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then 57 | echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 58 | echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 59 | return 1 60 | fi 61 | fi 62 | else 63 | JAVACMD="$( 64 | 'set' +e 65 | 'unset' -f command 2>/dev/null 66 | 'command' -v java 67 | )" || : 68 | JAVACCMD="$( 69 | 'set' +e 70 | 'unset' -f command 2>/dev/null 71 | 'command' -v javac 72 | )" || : 73 | 74 | if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then 75 | echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 76 | return 1 77 | fi 78 | fi 79 | } 80 | 81 | # hash string like Java String::hashCode 82 | hash_string() { 83 | str="${1:-}" h=0 84 | while [ -n "$str" ]; do 85 | char="${str%"${str#?}"}" 86 | h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) 87 | str="${str#?}" 88 | done 89 | printf %x\\n $h 90 | } 91 | 92 | verbose() { :; } 93 | [ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } 94 | 95 | die() { 96 | printf %s\\n "$1" >&2 97 | exit 1 98 | } 99 | 100 | trim() { 101 | # MWRAPPER-139: 102 | # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. 103 | # Needed for removing poorly interpreted newline sequences when running in more 104 | # exotic environments such as mingw bash on Windows. 105 | printf "%s" "${1}" | tr -d '[:space:]' 106 | } 107 | 108 | # parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties 109 | while IFS="=" read -r key value; do 110 | case "${key-}" in 111 | distributionUrl) distributionUrl=$(trim "${value-}") ;; 112 | distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; 113 | esac 114 | done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" 115 | [ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" 116 | 117 | case "${distributionUrl##*/}" in 118 | maven-mvnd-*bin.*) 119 | MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ 120 | case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in 121 | *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; 122 | :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; 123 | :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; 124 | :Linux*x86_64*) distributionPlatform=linux-amd64 ;; 125 | *) 126 | echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 127 | distributionPlatform=linux-amd64 128 | ;; 129 | esac 130 | distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" 131 | ;; 132 | maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; 133 | *) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; 134 | esac 135 | 136 | # apply MVNW_REPOURL and calculate MAVEN_HOME 137 | # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ 138 | [ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" 139 | distributionUrlName="${distributionUrl##*/}" 140 | distributionUrlNameMain="${distributionUrlName%.*}" 141 | distributionUrlNameMain="${distributionUrlNameMain%-bin}" 142 | MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" 143 | MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" 144 | 145 | exec_maven() { 146 | unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : 147 | exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" 148 | } 149 | 150 | if [ -d "$MAVEN_HOME" ]; then 151 | verbose "found existing MAVEN_HOME at $MAVEN_HOME" 152 | exec_maven "$@" 153 | fi 154 | 155 | case "${distributionUrl-}" in 156 | *?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; 157 | *) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; 158 | esac 159 | 160 | # prepare tmp dir 161 | if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then 162 | clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } 163 | trap clean HUP INT TERM EXIT 164 | else 165 | die "cannot create temp dir" 166 | fi 167 | 168 | mkdir -p -- "${MAVEN_HOME%/*}" 169 | 170 | # Download and Install Apache Maven 171 | verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." 172 | verbose "Downloading from: $distributionUrl" 173 | verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" 174 | 175 | # select .zip or .tar.gz 176 | if ! command -v unzip >/dev/null; then 177 | distributionUrl="${distributionUrl%.zip}.tar.gz" 178 | distributionUrlName="${distributionUrl##*/}" 179 | fi 180 | 181 | # verbose opt 182 | __MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' 183 | [ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v 184 | 185 | # normalize http auth 186 | case "${MVNW_PASSWORD:+has-password}" in 187 | '') MVNW_USERNAME='' MVNW_PASSWORD='' ;; 188 | has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; 189 | esac 190 | 191 | if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then 192 | verbose "Found wget ... using wget" 193 | wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" 194 | elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then 195 | verbose "Found curl ... using curl" 196 | curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" 197 | elif set_java_home; then 198 | verbose "Falling back to use Java to download" 199 | javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" 200 | targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" 201 | cat >"$javaSource" <<-END 202 | public class Downloader extends java.net.Authenticator 203 | { 204 | protected java.net.PasswordAuthentication getPasswordAuthentication() 205 | { 206 | return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); 207 | } 208 | public static void main( String[] args ) throws Exception 209 | { 210 | setDefault( new Downloader() ); 211 | java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); 212 | } 213 | } 214 | END 215 | # For Cygwin/MinGW, switch paths to Windows format before running javac and java 216 | verbose " - Compiling Downloader.java ..." 217 | "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" 218 | verbose " - Running Downloader.java ..." 219 | "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" 220 | fi 221 | 222 | # If specified, validate the SHA-256 sum of the Maven distribution zip file 223 | if [ -n "${distributionSha256Sum-}" ]; then 224 | distributionSha256Result=false 225 | if [ "$MVN_CMD" = mvnd.sh ]; then 226 | echo "Checksum validation is not supported for maven-mvnd." >&2 227 | echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 228 | exit 1 229 | elif command -v sha256sum >/dev/null; then 230 | if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then 231 | distributionSha256Result=true 232 | fi 233 | elif command -v shasum >/dev/null; then 234 | if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then 235 | distributionSha256Result=true 236 | fi 237 | else 238 | echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 239 | echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 240 | exit 1 241 | fi 242 | if [ $distributionSha256Result = false ]; then 243 | echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 244 | echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 245 | exit 1 246 | fi 247 | fi 248 | 249 | # unzip and move 250 | if command -v unzip >/dev/null; then 251 | unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" 252 | else 253 | tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" 254 | fi 255 | printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" 256 | mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" 257 | 258 | clean || : 259 | exec_maven "$@" 260 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/db/repository/CallMethodRepository.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.db.repository; 2 | 3 | import io.bitdive.mcpserver.db.entity.CallMethod; 4 | import io.bitdive.mcpserver.dto.hierarchy_method.data.CallMethodRepositoryDTO; 5 | import io.bitdive.mcpserver.dto.hierarchy_method.data.FindClassAndMethodBetweenDateDTO; 6 | import io.bitdive.mcpserver.dto.last_call.LastCallModuleAndServiceDTO; 7 | import org.springframework.data.jpa.repository.JpaRepository; 8 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 9 | import org.springframework.data.jpa.repository.Query; 10 | 11 | import java.util.List; 12 | import java.util.Optional; 13 | import java.util.UUID; 14 | 15 | public interface CallMethodRepository extends JpaRepository, JpaSpecificationExecutor { 16 | 17 | 18 | @Query(value = """ 19 | with method_call_base as (SELECT v.module_id, 20 | v.service_id, 21 | v.class_id, 22 | v.method_id, 23 | v.call_time_date_start 24 | 25 | FROM call_method v 26 | WHERE v.span_id = :span_id 27 | AND v.trace_id = :trace_id 28 | AND v.message_id = :message_id 29 | ), 30 | method_call_between as (select cm.* , mcb.call_time_date_start as call_time_date_start_base 31 | from call_method cm, 32 | method_call_base mcb 33 | where cm.module_id = mcb.module_id 34 | and cm.service_id = mcb.service_id 35 | and cm.class_id = mcb.class_id 36 | and cm.method_id = mcb.method_id 37 | and cm.call_time_date_start BETWEEN 38 | mcb.call_time_date_start - (INTERVAL '1 min' * :deltaFind) 39 | AND 40 | mcb.call_time_date_start + (INTERVAL '1 min' * :deltaFind)) 41 | select distinct mm.* from ( (select mcb.module_id as moduleId, 42 | mcb.service_id as serviceId, 43 | mcb.class_id as classId, 44 | mcb.method_id as methodId , 45 | mcb.call_time_delta as callTimeDelta, 46 | mcb.call_time_date_start as callTimeDateStart, 47 | mcb.span_id as spanId, 48 | mcb.trace_id as traceId, 49 | mcb.message_id as messageId 50 | from method_call_between mcb 51 | where mcb.call_time_date_start 52 | between mcb.call_time_date_start- (INTERVAL '1 min' * :deltaFind) and mcb.call_time_date_start_base 53 | order by mcb.call_time_date_start desc LIMIT 10) 54 | union all 55 | (select mcb.module_id as moduleId, 56 | mcb.service_id as serviceId, 57 | mcb.class_id as classId, 58 | mcb.method_id as methodId , 59 | mcb.call_time_delta as callTimeDelta, 60 | mcb.call_time_date_start as callTimeDateStart, 61 | mcb.span_id as spanId, 62 | mcb.trace_id as traceId, 63 | mcb.message_id as messageId 64 | from method_call_between mcb 65 | where mcb.call_time_date_start 66 | between mcb.call_time_date_start_base and mcb.call_time_date_start + (INTERVAL '1 min' * :deltaFind) 67 | order by mcb.call_time_date_start LIMIT 10)) as mm 68 | """, nativeQuery = true) 69 | List findHistCallMethod( 70 | UUID span_id, 71 | UUID trace_id, 72 | UUID message_id, 73 | Integer deltaFind 74 | ); 75 | 76 | 77 | @Query(value = """ 78 | WITH RECURSIVE call_hierarchy AS ( 79 | SELECT * 80 | FROM call_method c 81 | WHERE message_id = :messageId 82 | AND in_point_flag = TRUE 83 | AND c.call_time_date_start BETWEEN 84 | CAST(:dateCall AS TIMESTAMPTZ) AND CAST(:dateCall AS TIMESTAMPTZ) + INTERVAL '1 day' 85 | UNION ALL 86 | SELECT cm.* 87 | FROM call_method cm 88 | INNER JOIN call_hierarchy ch 89 | ON cm.call_id_parent = ch.message_id 90 | WHERE cm.call_time_date_start BETWEEN 91 | CAST(:dateCall AS TIMESTAMPTZ) AND CAST(:dateCall AS TIMESTAMPTZ) + INTERVAL '1 day' 92 | ) 93 | SELECT 94 | c.message_id AS message_id, 95 | c.trace_id AS trace_id, 96 | c.span_id AS span_id, 97 | c.call_id_parent AS call_id_parent, 98 | m.name AS module_name, 99 | sm.name AS service_name, 100 | cns.name AS class_name, 101 | mcn.method_name AS method_name, 102 | ot.operation_type AS operation_type, 103 | c.args AS args, 104 | c.method_return AS method_return, 105 | c.error_call_message AS error_call_message, 106 | c.call_time_date_start AS call_time_date_start, 107 | c.call_time_date_end AS call_time_date_end, 108 | c.in_point_flag AS in_point_flag, 109 | c.call_time_delta AS call_time_delta, 110 | c.code_response AS code_response, 111 | c.date_insert AS date_insert, 112 | lv.library_version AS library_version 113 | FROM call_hierarchy c 114 | JOIN module m ON c.module_id = m.id 115 | JOIN service_for_module sm ON c.service_id = sm.id 116 | JOIN class_name_for_service cns ON c.class_id = cns.id 117 | JOIN method_for_class_name mcn ON c.method_id = mcn.id 118 | JOIN operation_type ot ON c.operation_type_id = ot.id 119 | JOIN library_version lv ON c.library_version_id = lv.id 120 | """, nativeQuery = true) 121 | List findTreeCall(UUID messageId); 122 | 123 | 124 | @Query(value = """ 125 | WITH RECURSIVE call_hierarchy AS ( 126 | SELECT * 127 | FROM call_method c 128 | WHERE message_id = :messageId 129 | AND in_point_flag = TRUE 130 | UNION ALL 131 | SELECT cm.* 132 | FROM call_method cm 133 | INNER JOIN call_hierarchy ch 134 | ON cm.call_id_parent = ch.message_id 135 | ) 136 | SELECT 137 | c.message_id as messageId, 138 | c.trace_id as traceId, 139 | c.span_id as spanId, 140 | cns.name as className, 141 | mcn.method_name as methodName, 142 | c.call_id_parent as callIdParent, 143 | decrypt_decompress(c.args , :keyDecrypt) as args, 144 | c.call_time_date_start as callTimeDateStart, 145 | c.call_time_date_end as callTimeDateEnd, 146 | decrypt_decompress(c.method_return , :keyDecrypt) as methodReturn, 147 | decrypt_decompress(c.error_call_message , :keyDecrypt) as errorCallMessage, 148 | m.name as moduleName, 149 | sm.name as serviceName, 150 | c.in_point_flag as inPointFlag, 151 | c.call_time_delta as callTimeDelta, 152 | ot.operation_type as operationType, 153 | c.code_response as codeResponse, 154 | c.date_insert as dateInsert, 155 | lv.library_version as libraryVersion, 156 | c.service_call_id as serviceCallId 157 | FROM call_hierarchy c 158 | JOIN module m ON c.module_id = m.id 159 | JOIN service_for_module sm ON c.service_id = sm.id 160 | JOIN class_name_for_service cns ON c.class_id = cns.id 161 | JOIN method_for_class_name mcn ON c.method_id = mcn.id 162 | JOIN operation_type ot ON c.operation_type_id = ot.id 163 | JOIN library_version lv ON c.library_version_id = lv.id 164 | """, nativeQuery = true) 165 | List findTreeCall(UUID messageId, String keyDecrypt); 166 | 167 | @Query(value = """ 168 | SELECT 169 | c.in_point_message_id as inPointMessageId 170 | FROM call_method c 171 | JOIN module m ON c.module_id = m.id 172 | JOIN service_for_module sm ON c.service_id = sm.id 173 | JOIN class_name_for_service cns ON c.class_id = cns.id 174 | JOIN method_for_class_name mcn ON c.method_id = mcn.id 175 | where 176 | c.call_time_date_start BETWEEN CAST(:dateCallStart AS TIMESTAMPTZ) AND CAST(:dateCallEnd AS TIMESTAMPTZ) and 177 | cns.name=:className and 178 | mcn.method_name=:methodName 179 | """, 180 | nativeQuery = true) 181 | List findClassAndMethodBetweenDate(String className, String methodName, String dateCallStart, String dateCallEnd); 182 | 183 | @Query(value = """ 184 | select cm.message_id as messageId , 185 | m.name as methodName , 186 | sfm.name as serviceName , 187 | cnfs.name as className , 188 | mfcn.method_name as methodName , 189 | cm.call_time_date_start as callDateTime 190 | from call_method cm 191 | left join module m on cm.module_id=m.id 192 | left join service_for_module sfm on sfm.module_id=cm.module_id and sfm.id=cm.service_id 193 | left join class_name_for_service cnfs on cnfs.service_id=sfm.id and cnfs.id=cm.class_id 194 | left join method_for_class_name mfcn on mfcn.class_id=cnfs.id and mfcn.id=cm.method_id and mfcn.isinpoint=true 195 | where cm.service_node_id=:nodeId and cm.in_point_flag=true 196 | """,nativeQuery = true) 197 | List lastCallModuleAndService(Long nodeId); 198 | } 199 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/utils/UtilsCovert.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.utils; 2 | 3 | import io.bitdive.mcpserver.dto.hierarchy_method.HierarchyMethodUIDto; 4 | import io.bitdive.mcpserver.dto.hierarchy_method.QueueCall; 5 | import io.bitdive.mcpserver.dto.hierarchy_method.RestCall; 6 | import io.bitdive.mcpserver.dto.hierarchy_method.SQLCall; 7 | import io.bitdive.mcpserver.dto.hierarchy_method.data.*; 8 | import lombok.Getter; 9 | import lombok.RequiredArgsConstructor; 10 | 11 | import java.util.*; 12 | import java.util.stream.Collectors; 13 | 14 | @RequiredArgsConstructor 15 | public class UtilsCovert { 16 | 17 | 18 | public static List convertModuleToUI(List ModuleList){ 19 | 20 | // Группируем данные по модулям, сервисам и классам 21 | Map>>> groupedData = new HashMap<>(); 22 | 23 | for (ModuleRepositoryDTO result : ModuleList) { 24 | String moduleName = result.getModule(); 25 | String serviceName = result.getService(); 26 | String className = result.getClassName(); 27 | String methodName = result.getMethod(); 28 | Long isPointId = result.getInPointId(); 29 | boolean isInPoint = result.getIsInPoint(); 30 | 31 | groupedData 32 | .computeIfAbsent(moduleName, k -> new HashMap<>()) 33 | .computeIfAbsent(serviceName, k -> new HashMap<>()) 34 | .computeIfAbsent(className, k -> new ArrayList<>()) 35 | .add(new InPointUIDto(isPointId, methodName, isInPoint)); 36 | } 37 | 38 | return groupedData.entrySet().stream() 39 | .map(moduleEntry -> { 40 | String moduleName = moduleEntry.getKey(); 41 | Set serviceUISet = moduleEntry.getValue().entrySet().stream() 42 | .map(serviceEntry -> { 43 | String serviceName = serviceEntry.getKey(); 44 | Set classNameUISet = serviceEntry.getValue().entrySet().stream() 45 | .map(classEntry -> { 46 | String className = classEntry.getKey(); 47 | Set inPointUISet = new HashSet<>(classEntry.getValue()); 48 | return new ClassNameUIDto(className, inPointUISet); 49 | }) 50 | .collect(Collectors.toSet()); 51 | 52 | return new ServiceUIDto(serviceName, classNameUISet); 53 | }) 54 | .collect(Collectors.toSet()); 55 | 56 | return new ModuleUIDto(moduleName, serviceUISet); 57 | }) 58 | .collect(Collectors.toList()); 59 | } 60 | 61 | 62 | public static CallMethodUIDto convertCallMethodToUI(CallMethodRepositoryDTO callMethod) { 63 | if (callMethod == null) { 64 | return null; 65 | } 66 | var dto = new CallMethodUIDto(); 67 | dto.setId(callMethod.getMessageId()); 68 | dto.setTraceId(callMethod.getTraceId()); 69 | dto.setClassName(callMethod.getClassName()); 70 | dto.setMethodName(callMethod.getMethodName()); 71 | dto.setArgs(callMethod.getArgs()); // Assuming ParamMethodDto is already suitable for DTO 72 | // dto.setMessageKafkaCallTime(new MessageKafkaCallTimeUIDto(callMethod.getCallTimeDateStart(), callMethod.getCallTimeDateEnd(), callMethod.getCallTimeDelta())); 73 | 74 | // dto.setParentMethod(toDto(callMethod.getParentMethod())); 75 | dto.setMethodReturn(callMethod.getMethodReturn()); 76 | dto.setErrorCallMessage(callMethod.getErrorCallMessage()); 77 | dto.setLibraryVersion(callMethod.getLibraryVersion()); 78 | dto.setLibraryVersion(callMethod.getLibraryVersion()); 79 | return dto; 80 | } 81 | 82 | 83 | public static HierarchyMethodUIDto buildDependencyTree(List callMethods) { 84 | if (callMethods == null || callMethods.isEmpty()) { 85 | return null; 86 | } 87 | 88 | Map dtoMap = new HashMap<>(); 89 | for (CallMethodDTO cm : callMethods) { 90 | HierarchyMethodUIDto dto = HierarchyMethodUIDto.builder() 91 | .messageId(cm.getId()) 92 | .className(cm.getClassName()) 93 | .methodName(cm.getMethodName()) 94 | .args(cm.getArgs()) 95 | .traceId(cm.getTraceId()) 96 | .spanId(cm.getSpanId()) 97 | .callTimeDateStart(cm.getCallTimeDateStart()) 98 | .callTimeDateEnd(cm.getCallTimeDateEnd()) 99 | .callTimeDelta(cm.getCallTimeDelta()) 100 | .methodReturn(cm.getMethodReturn()) 101 | .errorCallMessage(cm.getErrorCallMessage()) 102 | .moduleName(cm.getModuleName()) 103 | .serviceName(cm.getServiceName()) 104 | .inPointFlag(cm.getInPointFlag()) 105 | .childCalls(new ArrayList<>()) 106 | .sqlCalls(cm.getCallMethodSqlList().stream() 107 | .map(callMethodSql -> 108 | SQLCall.builder() 109 | .messageId(callMethodSql.getMessageId()) 110 | .sql(combineSqlAndParams(callMethodSql.getCallMethodSqlText(), callMethodSql.getCallMethodSqlParam())) 111 | .callTimeDateStart(callMethodSql.getCallTimeDateStart()) 112 | .callTimeDateEnd(callMethodSql.getCallTimeDateEnd()) 113 | .callTimeDelta(callMethodSql.getCallTimeDelta()) 114 | .errorCallMessage(callMethodSql.getErrorCallMessage()) 115 | .libraryVersion(callMethodSql.getLibraryVersion()) 116 | .build() 117 | ).toList()) 118 | .restCalls(cm.getCallMethodRests().stream() 119 | .map(callMethodRest -> RestCall.builder() 120 | .messageId(callMethodRest.getMessageId()) 121 | .uri(callMethodRest.getUri()) 122 | .callTimeDateStart(callMethodRest.getDateStart()) 123 | .callTimeDateEnd(callMethodRest.getDateEnd()) 124 | .callTimeDelta(callMethodRest.getCallTimeDelta()) 125 | .method(callMethodRest.getMethodId()) 126 | .headers(callMethodRest.getHeaders()) 127 | .body(callMethodRest.getBody()) 128 | .statusCode(callMethodRest.getStatusCode()) 129 | .responseHeaders(callMethodRest.getResponseHeaders()) 130 | .responseBody(callMethodRest.getResponseBody()) 131 | .errorCallMessage(callMethodRest.getErrorCall()) 132 | .libraryVersion(callMethodRest.getLibraryVersion()) 133 | .build()) 134 | .toList()) 135 | .restCallMethod( 136 | cm.getRestCallMethod()==null?null: RestCall.builder() 137 | //.messageId(cm.getRestCallMethod().getMessageId()) 138 | .uri(cm.getRestCallMethod().getUri()) 139 | .callTimeDateStart(cm.getRestCallMethod().getDateStart()) 140 | .callTimeDateEnd(cm.getRestCallMethod().getDateEnd()) 141 | .callTimeDelta(cm.getRestCallMethod().getCallTimeDelta()) 142 | .method(cm.getRestCallMethod().getMethodId()) 143 | .headers(cm.getRestCallMethod().getHeaders()) 144 | .body(cm.getRestCallMethod().getBody()) 145 | .statusCode(cm.getRestCallMethod().getStatusCode()) 146 | .responseHeaders(cm.getRestCallMethod().getResponseHeaders()) 147 | .responseBody(cm.getRestCallMethod().getResponseBody()) 148 | .errorCallMessage(cm.getRestCallMethod().getErrorCall()) 149 | .libraryVersion(cm.getRestCallMethod().getLibraryVersion()) 150 | .build() 151 | ) 152 | .queueCalls(cm.getCallMethodQueue().stream().map(callMethodQueueSendDTO -> 153 | QueueCall.builder() 154 | .messageId(callMethodQueueSendDTO.getMessageId()) 155 | .callTimeDateStart(callMethodQueueSendDTO.getCallTimeDateStart()) 156 | .callTimeDateEnd(callMethodQueueSendDTO.getCallTimeDateEnd()) 157 | .callTimeDelta(callMethodQueueSendDTO.getCallTimeDelta().doubleValue()) 158 | .messageBody(callMethodQueueSendDTO.getMessageBody()) 159 | .queueTopic(callMethodQueueSendDTO.getTopicName()) 160 | .queueServer(callMethodQueueSendDTO.getQueueServer()) 161 | .libraryVersion(callMethodQueueSendDTO.getLibraryVersion()) 162 | .errorCall(callMethodQueueSendDTO.getErrorCall()) 163 | .isError(callMethodQueueSendDTO.getIsError()) 164 | .build() 165 | ).toList()) 166 | .codeResponse(cm.getCodeResponse()) 167 | .operationType(cm.getOperationType()) 168 | .libraryVersion(cm.getLibraryVersion()) 169 | .build(); 170 | dtoMap.put(cm.getId(), dto); 171 | } 172 | 173 | HierarchyMethodUIDto root = null; 174 | 175 | for (CallMethodDTO cm : callMethods) { 176 | HierarchyMethodUIDto currentDto = dtoMap.get(cm.getId()); 177 | var parentId = cm.getCallIdParent(); 178 | 179 | if (parentId == null) { 180 | if (root == null) { 181 | root = currentDto; 182 | } else { 183 | System.err.println("Обнаружено несколько корневых узлов. Дополнительные корни будут игнорироваться."); 184 | } 185 | } else { 186 | HierarchyMethodUIDto parentDto = dtoMap.get(parentId); 187 | if (parentDto != null) { 188 | parentDto.getChildCalls().add(currentDto); 189 | } else { 190 | System.err.println("Родитель с messageId " + parentId + " не найден для messageId " + cm.getId()); 191 | if (root == null) { 192 | root = currentDto; 193 | } 194 | } 195 | } 196 | } 197 | 198 | return root; 199 | } 200 | 201 | private static String combineSqlAndParams(String sql, String paramString) { 202 | try { 203 | if (paramString == null) paramString = ""; 204 | if (sql == null) sql = ""; 205 | 206 | paramString = paramString.trim(); 207 | 208 | if (paramString.startsWith("{")) { 209 | paramString = paramString.substring(1); 210 | } 211 | if (paramString.endsWith("}")) { 212 | paramString = paramString.substring(0, paramString.length() - 1); 213 | } 214 | 215 | String[] chunks = paramString.split("\\},\\{"); 216 | 217 | // 2. Парсим каждый кусочек в (index, value, type) 218 | List paramList = new ArrayList<>(); 219 | 220 | for (String chunk : chunks) { 221 | String[] parts = chunk.split(",", 3); 222 | 223 | if (parts.length < 3) { 224 | continue; 225 | } 226 | 227 | String indexStr = parts[0].trim(); 228 | String value = parts[1].trim(); 229 | String type = parts[2].trim(); 230 | 231 | int paramIndex = Integer.parseInt(indexStr); 232 | String paramType = type.toUpperCase(); 233 | 234 | paramList.add(new Param(paramIndex, value, paramType)); 235 | } 236 | 237 | paramList.sort(Comparator.comparingInt(Param::getIndex)); 238 | 239 | 240 | for (Param p : paramList) { 241 | String replacedValue; 242 | switch (p.type) { 243 | case "INT": 244 | case "INTEGER": 245 | case "LONG": 246 | case "DOUBLE": 247 | case "NULL": 248 | case "FLOAT": 249 | replacedValue = p.value; 250 | break; 251 | default: 252 | replacedValue = "'" + p.value + "'"; 253 | break; 254 | } 255 | sql = sql.replaceFirst("\\?", replacedValue); 256 | } 257 | 258 | return sql; 259 | } catch (Exception e) { 260 | return sql + "\n" + paramString; 261 | } 262 | } 263 | 264 | @Getter 265 | private static class Param { 266 | private int index; 267 | private String value; 268 | private String type; 269 | 270 | public Param(int index, String value, String type) { 271 | this.index = index; 272 | this.value = value; 273 | this.type = type; 274 | } 275 | } 276 | 277 | } 278 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/mcpserver/component/AnalyticsService.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.mcpserver.component; 2 | 3 | import io.bitdive.mcpserver.config.securety.dto.CurrentUser; 4 | import io.bitdive.mcpserver.db.entity.ClassCallAnalytics; 5 | import io.bitdive.mcpserver.db.entity.InPointCallAnalytics; 6 | import io.bitdive.mcpserver.db.entity.ModuleCallAnalytics; 7 | import io.bitdive.mcpserver.db.entity.ServiceCallAnalytics; 8 | import io.bitdive.mcpserver.db.repository.ClassCallAnalyticsRepository; 9 | import io.bitdive.mcpserver.db.repository.InPointCallAnalyticsRepository; 10 | import io.bitdive.mcpserver.db.repository.ModuleCallAnalyticsRepository; 11 | import io.bitdive.mcpserver.db.repository.ServiceCallAnalyticsRepository; 12 | import io.bitdive.mcpserver.dto.hierarchy_method.heap_map.ClassAnalyticsDTO; 13 | import io.bitdive.mcpserver.dto.hierarchy_method.heap_map.InPointAnalyticsDTO; 14 | import io.bitdive.mcpserver.dto.hierarchy_method.heap_map.ModuleAnalyticsDTO; 15 | import io.bitdive.mcpserver.dto.hierarchy_method.heap_map.ServiceAnalyticsDTO; 16 | import lombok.RequiredArgsConstructor; 17 | import org.springframework.stereotype.Service; 18 | 19 | import java.time.OffsetDateTime; 20 | import java.util.Collections; 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.stream.Collectors; 24 | 25 | import static io.bitdive.mcpserver.utils.UserViewModule.isViewForModule; 26 | 27 | @Service 28 | @RequiredArgsConstructor 29 | public class AnalyticsService { 30 | 31 | private final ModuleCallAnalyticsRepository moduleRepository; 32 | private final ServiceCallAnalyticsRepository serviceRepository; 33 | private final ClassCallAnalyticsRepository classRepository; 34 | private final InPointCallAnalyticsRepository inPointRepository; 35 | 36 | 37 | private String nullToEmpty(String value) { 38 | return value == null ? "" : value; 39 | } 40 | 41 | public List getAnalyticsData(Integer lastMinutes, CurrentUser currentUser) { 42 | OffsetDateTime end = OffsetDateTime.now(); 43 | OffsetDateTime start = end.minusMinutes(lastMinutes); 44 | 45 | List modules = moduleRepository.findByAnalysisTimestampBetween(start, end) 46 | .stream().filter(moduleCallAnalytics ->isViewForModule(currentUser, moduleCallAnalytics.getModuleName())) 47 | .toList(); 48 | 49 | List services = serviceRepository.findByAnalysisTimestampBetween(start, end); 50 | List classes = classRepository.findByAnalysisTimestampBetween(start, end); 51 | List inPoints = inPointRepository.findByAnalysisTimestampBetween(start, end); 52 | 53 | // Group services by moduleName and serviceName 54 | Map> servicesGrouped = services.stream() 55 | .collect(Collectors.groupingBy(svc -> svc.getModuleName() + ":" + svc.getServiceName())); 56 | 57 | // Group classes by moduleName, serviceName, and className 58 | Map> classesGrouped = classes.stream() 59 | .collect(Collectors.groupingBy(cls -> cls.getModuleName() + ":" + cls.getServiceName() + ":" + cls.getClassName())); 60 | 61 | // Group inPoints by moduleName, serviceName, className, and inPointName 62 | Map> inPointsGrouped = inPoints.stream() 63 | .collect(Collectors.groupingBy(ip -> ip.getModuleName() + ":" + ip.getServiceName() + ":" + ip.getClassName() + ":" + ip.getMethodName())); 64 | 65 | // Build the modules DTO 66 | return modules.stream() 67 | .collect(Collectors.groupingBy(ModuleCallAnalytics::getModuleName)) 68 | .entrySet().stream() 69 | .map(entry -> { 70 | String moduleName = entry.getKey(); 71 | List moduleRecords = entry.getValue(); 72 | 73 | ModuleCallAnalytics actualModule = moduleRecords.get(moduleRecords.size() - 1); 74 | List moduleHistory = moduleRecords.subList(0, moduleRecords.size()).stream() 75 | .map(moduleCallAnalytics -> mapToModuleDTO(moduleCallAnalytics,null,null)) 76 | .collect(Collectors.toList()); 77 | 78 | // Process services for this module 79 | List moduleServices = servicesGrouped.entrySet().stream() 80 | .filter(svcEntry -> svcEntry.getKey().startsWith(moduleName + ":")) 81 | .map(svcEntry -> { 82 | List serviceRecords = svcEntry.getValue(); 83 | ServiceCallAnalytics actualService = serviceRecords.get(serviceRecords.size() - 1); 84 | List serviceHistory = serviceRecords.subList(0, serviceRecords.size()).stream() 85 | .map(serviceCallAnalytics -> mapToServiceDTO(serviceCallAnalytics,null,null)) 86 | .collect(Collectors.toList()); 87 | 88 | // Process classes for this service 89 | String serviceName = actualService.getServiceName(); 90 | List serviceClasses = classesGrouped.entrySet().stream() 91 | .filter(clsEntry -> clsEntry.getKey().startsWith(moduleName + ":" + serviceName + ":")) 92 | .map(clsEntry -> { 93 | List classRecords = clsEntry.getValue(); 94 | ClassCallAnalytics actualClass = classRecords.get(classRecords.size() - 1); 95 | List classHistory = classRecords.subList(0, classRecords.size()).stream() 96 | .map(classCallAnalytics -> mapToClassDTO(classCallAnalytics,null,null)) 97 | .collect(Collectors.toList()); 98 | 99 | // Process inPoints for this class 100 | String className = actualClass.getClassName(); 101 | List classInPoints = inPointsGrouped.entrySet().stream() 102 | .filter(ipEntry -> ipEntry.getKey().startsWith(moduleName + ":" + serviceName + ":" + className + ":")) 103 | .map(ipEntry -> { 104 | List inPointRecords = ipEntry.getValue(); 105 | InPointCallAnalytics actualInPoint = inPointRecords.get(inPointRecords.size() - 1); 106 | List inPointHistory = inPointRecords.subList(0, inPointRecords.size()).stream() 107 | .map(inPointCallAnalytics -> mapToInPointDTO(inPointCallAnalytics,null,null)) 108 | .collect(Collectors.toList()); 109 | 110 | InPointAnalyticsDTO inPointDTO = this.mapToInPointDTO(actualInPoint, 111 | actualModule.getAnalysisTimestamp().minusSeconds(5), 112 | actualModule.getAnalysisTimestamp().plusSeconds(5) 113 | ); 114 | return inPointDTO; 115 | }) 116 | .collect(Collectors.toList()); 117 | 118 | ClassAnalyticsDTO classDTO = this.mapToClassDTO(actualClass, 119 | actualModule.getAnalysisTimestamp().minusSeconds(5), 120 | actualModule.getAnalysisTimestamp().plusSeconds(5) 121 | ); 122 | classDTO.setInPoints(classInPoints); 123 | return classDTO; 124 | }) 125 | .collect(Collectors.toList()); 126 | 127 | ServiceAnalyticsDTO serviceDTO = this.mapToServiceDTO(actualService, 128 | actualModule.getAnalysisTimestamp().minusSeconds(5), 129 | actualModule.getAnalysisTimestamp().plusSeconds(5) 130 | ); 131 | serviceDTO.setClasses(serviceClasses); 132 | return serviceDTO; 133 | }) 134 | .collect(Collectors.toList()); 135 | 136 | ModuleAnalyticsDTO moduleDTO = this.mapToModuleDTO(actualModule, 137 | actualModule.getAnalysisTimestamp().minusSeconds(5), 138 | actualModule.getAnalysisTimestamp().plusSeconds(5) 139 | ); 140 | moduleDTO.setServices(moduleServices); 141 | return moduleDTO; 142 | }) 143 | .collect(Collectors.toList()); 144 | } 145 | 146 | private ModuleAnalyticsDTO mapToModuleDTO(ModuleCallAnalytics module, OffsetDateTime start, OffsetDateTime end) { 147 | ModuleAnalyticsDTO dto = new ModuleAnalyticsDTO( 148 | module.getModuleName(), 149 | module.getAnalysisTimestamp(), 150 | module.getErrorCount(), 151 | module.getCallCountWeb(), 152 | module.getAvgCallTimeWeb(), 153 | module.getCallCountScheduler(), 154 | module.getAvgCallTimeScheduler(), 155 | module.getSqlCallCount(), 156 | module.getAvgSqlCallTime(), 157 | module.getSqlErrorCount(), 158 | module.getRestCallCount(), 159 | module.getAvgRestCallTime(), 160 | module.getRestErrorCount(), 161 | module.getCount2xx(), 162 | module.getCount3xx(), 163 | module.getCount4xx(), 164 | module.getCount5xx(), 165 | module.getQueueSendCount(), 166 | module.getAvgQueueSendTime(), 167 | module.getQueueSendErrorCount(), 168 | module.getQueueConsumerCount(), 169 | module.getQueueConsumerAvgCallTime(), 170 | module.getQueueConsumerErrorCount(), 171 | null // services will be set later 172 | ); 173 | return dto; 174 | } 175 | 176 | private ServiceAnalyticsDTO mapToServiceDTO(ServiceCallAnalytics service,OffsetDateTime start, OffsetDateTime end) { 177 | ServiceAnalyticsDTO dto = new ServiceAnalyticsDTO( 178 | service.getServiceName(), 179 | service.getAnalysisTimestamp(), 180 | service.getErrorCount(), 181 | service.getCallCountWeb(), 182 | service.getAvgCallTimeWeb(), 183 | service.getCallCountScheduler(), 184 | service.getAvgCallTimeScheduler(), 185 | service.getSqlCallCount(), 186 | service.getAvgSqlCallTime(), 187 | service.getSqlErrorCount(), 188 | service.getRestCallCount(), 189 | service.getAvgRestCallTime(), 190 | service.getRestErrorCount(), 191 | service.getCount2xx(), 192 | service.getCount3xx(), 193 | service.getCount4xx(), 194 | service.getCount5xx(), 195 | service.getQueueSendCount(), 196 | service.getAvgQueueSendTime(), 197 | service.getQueueSendErrorCount(), 198 | service.getQueueConsumerCount(), 199 | service.getQueueConsumerAvgCallTime(), 200 | service.getQueueConsumerErrorCount(), 201 | null // classes will be set later 202 | ); 203 | return dto; 204 | } 205 | 206 | private ClassAnalyticsDTO mapToClassDTO(ClassCallAnalytics cls,OffsetDateTime start, OffsetDateTime end) { 207 | ClassAnalyticsDTO dto = new ClassAnalyticsDTO( 208 | cls.getClassName(), 209 | cls.getAnalysisTimestamp(), 210 | cls.getErrorCount(), 211 | cls.getCallCountWeb(), 212 | cls.getAvgCallTimeWeb(), 213 | cls.getCallCountScheduler(), 214 | cls.getAvgCallTimeScheduler(), 215 | cls.getSqlCallCount(), 216 | cls.getAvgSqlCallTime(), 217 | cls.getSqlErrorCount(), 218 | cls.getRestCallCount(), 219 | cls.getAvgRestCallTime(), 220 | cls.getRestErrorCount(), 221 | cls.getCount2xx(), 222 | cls.getCount3xx(), 223 | cls.getCount4xx(), 224 | cls.getCount5xx(), 225 | cls.getQueueSendCount(), 226 | cls.getAvgQueueSendTime(), 227 | cls.getQueueSendErrorCount(), 228 | cls.getQueueConsumerCount(), 229 | cls.getQueueConsumerAvgCallTime(), 230 | cls.getQueueConsumerErrorCount(), 231 | null // inPoints will be set later 232 | ); 233 | return dto; 234 | } 235 | 236 | private InPointAnalyticsDTO mapToInPointDTO(InPointCallAnalytics inPoint,OffsetDateTime start, OffsetDateTime end) { 237 | InPointAnalyticsDTO dto = new InPointAnalyticsDTO( 238 | inPoint.getMethodName(), 239 | inPoint.getAnalysisTimestamp(), 240 | inPoint.getErrorCount(), 241 | inPoint.getCallCountWeb(), 242 | inPoint.getAvgCallTimeWeb(), 243 | inPoint.getCallCountScheduler(), 244 | inPoint.getAvgCallTimeScheduler(), 245 | inPoint.getSqlCallCount(), 246 | inPoint.getAvgSqlCallTime(), 247 | inPoint.getSqlErrorCount(), 248 | inPoint.getRestCallCount(), 249 | inPoint.getAvgRestCallTime(), 250 | inPoint.getRestErrorCount(), 251 | inPoint.getCount2xx(), 252 | inPoint.getCount3xx(), 253 | inPoint.getCount4xx(), 254 | inPoint.getCount5xx(), 255 | inPoint.getQueueSendCount(), 256 | inPoint.getAvgQueueSendTime(), 257 | inPoint.getQueueSendErrorCount(), 258 | inPoint.getQueueConsumerCount(), 259 | inPoint.getQueueConsumerAvgCallTime(), 260 | inPoint.getQueueConsumerErrorCount() 261 | ); 262 | return dto; 263 | } 264 | } 265 | --------------------------------------------------------------------------------