├── perf-monitoring-producer-spring-2.7 ├── src │ └── main │ │ ├── resources │ │ ├── META-INF │ │ │ ├── spring │ │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ │ │ ├── spring.factories │ │ │ └── spring-configuration-metadata.json │ │ └── config-profiling-default.yml │ │ └── java │ │ └── io │ │ └── bitdive │ │ ├── jvm_metrics │ │ ├── MeasurementDto.java │ │ ├── MetricDto.java │ │ ├── MetricsCollector.java │ │ └── MetricsService.java │ │ ├── aspect │ │ ├── YamlParserCondition.java │ │ ├── FeignClientAspect.java │ │ ├── SchedulerAspect.java │ │ ├── RepositoryAspect.java │ │ ├── StompSendToAspect.java │ │ ├── StompMessageMappingAspect.java │ │ └── KafkaListenerAspect.java │ │ ├── SpringConfigProfiling.java │ │ └── ByteBuddyAgentInitializer.java └── pom.xml ├── perf-monitoring-producer-spring-3 ├── src │ └── main │ │ ├── resources │ │ ├── META-INF │ │ │ ├── spring │ │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ │ │ ├── spring.factories │ │ │ └── spring-configuration-metadata.json │ │ └── config-profiling-default.yml │ │ └── java │ │ └── io │ │ └── bitdive │ │ ├── jvm_metrics │ │ ├── MeasurementDto.java │ │ ├── MetricDto.java │ │ ├── MetricsCollector.java │ │ └── MetricsService.java │ │ ├── aspect │ │ ├── YamlParserCondition.java │ │ ├── FeignClientAspect.java │ │ ├── RepositoryAspect.java │ │ ├── SchedulerAspect.java │ │ ├── StompSendToAspect.java │ │ ├── StompMessageMappingAspect.java │ │ └── KafkaListenerAspect.java │ │ ├── SpringConfigProfiling.java │ │ └── ByteBuddyAgentInitializer.java └── pom.xml ├── src └── main │ └── java │ └── io │ └── bitdive │ └── parent │ ├── parserConfig │ ├── LogLevelEnum.java │ ├── ConfigForServiceDTO.java │ ├── DefaultMonitoringValues.java │ ├── HttpsURLConnectionCustom.java │ └── ProfilingConfig.java │ ├── utils │ ├── LibraryVersionBitDive.java │ ├── hibernateConfig │ │ ├── HibernateVersionDetector.java │ │ └── HibernateModuleLoader.java │ ├── Pair.java │ ├── MethodTypeEnum.java │ └── ByteBuddyConfigLoader.java │ ├── dto │ ├── ParamMethodDto.java │ └── TraceMethodContext.java │ ├── anotations │ ├── MonitoringClass.java │ ├── NotMonitoring.java │ ├── NotMonitoringParamsClass.java │ └── NotMonitoringParamsField.java │ ├── trasirovka │ └── agent │ │ ├── utils │ │ ├── KafkaAgentStorage.java │ │ ├── MessageTypeEnum.java │ │ ├── ContextCallableCustom.java │ │ ├── objectMaperConfig │ │ │ ├── StreamPlaceholderSerializer.java │ │ │ ├── CollectionSizeLimiter.java │ │ │ ├── LimitedCollectionSerializer.java │ │ │ ├── PackageBasedSerializerModifier.java │ │ │ ├── MaskingFilter.java │ │ │ └── FlowDataToPlaceholderModule.java │ │ ├── ContextRunnableCustom.java │ │ ├── LoggerStatusContent.java │ │ ├── SQLUtils.java │ │ ├── CallableStatementParser.java │ │ └── RestUtils.java │ │ └── byte_buddy_agent │ │ ├── ByteBuddyAgentThreadCreator.java │ │ ├── ByteBuddyAgentThread.java │ │ ├── db │ │ └── ByteBuddyAgentSqlDriver.java │ │ ├── KafkaConsumerAgent.java │ │ ├── ByteBuddyAgentCoyoteInputStream.java │ │ ├── ByteBuddyAgentCatalinaResponse.java │ │ ├── ByteBuddySimpleClientHttpResponse.java │ │ ├── ByteBuddyAgentSpringRawWs.java │ │ └── ByteBuddyAgentKafkaInterceptor.java │ ├── message_producer │ ├── PemUtils.java │ ├── LocalCryptoService.java │ ├── HttpURLConnectionCustom.java │ ├── HttpsURLConnectionCustom.java │ └── LibraryLoggerConfig.java │ ├── init │ └── MonitoringStarting.java │ └── safety_config │ ├── VaultGettingConfig.java │ └── SSLContextCustomBitDive.java ├── .idea ├── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── vcs.xml ├── .gitignore ├── inspectionProfiles │ └── Project_Default.xml ├── misc.xml └── encodings.xml ├── LICENSE ├── .gitignore ├── README.md └── dependency-reduced-pom.xml /perf-monitoring-producer-spring-2.7/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.bitdive.SpringConfigProfiling -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.bitdive.SpringConfigProfiling -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/parserConfig/LogLevelEnum.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.parserConfig; 2 | 3 | public enum LogLevelEnum { 4 | ERRORS,INFO,DEBUG 5 | } 6 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/src/main/resources/config-profiling-default.yml: -------------------------------------------------------------------------------- 1 | application: 2 | moduleName: module1 3 | serviceName: config-profiling 4 | packedScanner: [ default ] 5 | 6 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-2.7/src/main/resources/config-profiling-default.yml: -------------------------------------------------------------------------------- 1 | application: 2 | moduleName: module1 3 | serviceName: config-profiling 4 | packedScanner: [ default ] 5 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/utils/LibraryVersionBitDive.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.utils; 2 | 3 | 4 | public class LibraryVersionBitDive { 5 | public static final String version = "1.3.4"; 6 | } 7 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-2.7/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.context.ApplicationContextInitializer=\ 2 | io.bitdive.ByteBuddyAgentInitializer 3 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 4 | io.bitdive.SpringConfigProfiling -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.context.ApplicationContextInitializer=\ 2 | io.bitdive.ByteBuddyAgentInitializer 3 | 4 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 5 | io.bitdive.SpringConfigProfiling -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/src/main/java/io/bitdive/jvm_metrics/MeasurementDto.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.jvm_metrics; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | @Getter 8 | @Setter 9 | @AllArgsConstructor 10 | public class MeasurementDto { 11 | private String statistic; 12 | private double value; 13 | } 14 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-2.7/src/main/java/io/bitdive/jvm_metrics/MeasurementDto.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.jvm_metrics; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | @Getter 8 | @Setter 9 | @AllArgsConstructor 10 | public class MeasurementDto { 11 | private String statistic; 12 | private double value; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/dto/ParamMethodDto.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Getter 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class ParamMethodDto { 11 | private int parIndex; 12 | private String paramType; 13 | private Object val; 14 | } -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-2.7/src/main/java/io/bitdive/jvm_metrics/MetricDto.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.jvm_metrics; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | @Getter 10 | @Setter 11 | public class MetricDto { 12 | private String name; 13 | private List measurements = new ArrayList<>(); 14 | } 15 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/src/main/java/io/bitdive/jvm_metrics/MetricDto.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.jvm_metrics; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | @Getter 10 | @Setter 11 | public class MetricDto { 12 | private String name; 13 | private List measurements = new ArrayList<>(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/anotations/MonitoringClass.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.anotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.TYPE, ElementType.METHOD}) 10 | public @interface MonitoringClass { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/anotations/NotMonitoring.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.anotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.TYPE, ElementType.METHOD}) 10 | public @interface NotMonitoring { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/utils/KafkaAgentStorage.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.utils; 2 | 3 | 4 | import java.util.Optional; 5 | 6 | public class KafkaAgentStorage { 7 | public static String KAFKA_BOOTSTRAP_PRODUCER_STRING; 8 | public static String KAFKA_BOOTSTRAP_CONSUMER_STRING; 9 | 10 | public static String getBootstrap() { 11 | return Optional.ofNullable(KAFKA_BOOTSTRAP_PRODUCER_STRING) 12 | .orElse(KAFKA_BOOTSTRAP_CONSUMER_STRING); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Elastic License 2.0 2 | 3 | This project is licensed under the Elastic License 2.0. 4 | 5 | You may use this software in compliance with the Elastic License 2.0. 6 | You may obtain a copy of the License at 7 | 8 | https://www.elastic.co/licensing/elastic-license 9 | 10 | Software distributed under this license is distributed on an "AS IS" basis, 11 | without warranties or conditions of any kind, either express or implied. 12 | See the Elastic License 2.0 for the specific language governing permissions and limitations under the License. 13 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/parserConfig/ConfigForServiceDTO.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.parserConfig; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import java.util.List; 9 | 10 | @Getter 11 | @Setter 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class ConfigForServiceDTO { 15 | private String moduleName; 16 | private String serviceName; 17 | private List packedScanner; 18 | private String serverUrl; 19 | private String token; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/utils/hibernateConfig/HibernateVersionDetector.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.utils.hibernateConfig; 2 | 3 | public class HibernateVersionDetector { 4 | public static Integer getHibernateMajorVersion() { 5 | try { 6 | Class versionClass = Class.forName("org.hibernate.Version"); 7 | String version = (String) versionClass.getDeclaredMethod("getVersionString").invoke(null); 8 | return Integer.parseInt(version.split("\\.")[0]); 9 | } catch (Exception e) { 10 | return null; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/src/main/java/io/bitdive/aspect/YamlParserCondition.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.aspect; 2 | 3 | import io.bitdive.parent.parserConfig.YamlParserConfig; 4 | import org.springframework.context.annotation.Condition; 5 | import org.springframework.context.annotation.ConditionContext; 6 | import org.springframework.core.type.AnnotatedTypeMetadata; 7 | 8 | public class YamlParserCondition implements Condition { 9 | @Override 10 | public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { 11 | return YamlParserConfig.isWork(); 12 | } 13 | } -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-2.7/src/main/java/io/bitdive/aspect/YamlParserCondition.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.aspect; 2 | 3 | import io.bitdive.parent.parserConfig.YamlParserConfig; 4 | import org.springframework.context.annotation.Condition; 5 | import org.springframework.context.annotation.ConditionContext; 6 | import org.springframework.core.type.AnnotatedTypeMetadata; 7 | 8 | public class YamlParserCondition implements Condition { 9 | @Override 10 | public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { 11 | return YamlParserConfig.isWork(); 12 | } 13 | } -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/utils/Pair.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.utils; 2 | 3 | public class Pair { 4 | 5 | private final K element0; 6 | private final V element1; 7 | 8 | public static Pair createPair(K element0, V element1) { 9 | return new Pair(element0, element1); 10 | } 11 | 12 | public Pair(K element0, V element1) { 13 | this.element0 = element0; 14 | this.element1 = element1; 15 | } 16 | 17 | public K getKey() { 18 | return element0; 19 | } 20 | 21 | public V getVal() { 22 | return element1; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | !**/src/main/**/target/ 4 | !**/src/test/**/target/ 5 | 6 | ### IntelliJ IDEA ### 7 | .idea/modules.xml 8 | .idea/jarRepositories.xml 9 | .idea/compiler.xml 10 | .idea/libraries/ 11 | *.iws 12 | *.iml 13 | *.ipr 14 | 15 | ### Eclipse ### 16 | .apt_generated 17 | .classpath 18 | .factorypath 19 | .project 20 | .settings 21 | .springBeans 22 | .sts4-cache 23 | 24 | ### NetBeans ### 25 | /nbproject/private/ 26 | /nbbuild/ 27 | /dist/ 28 | /nbdist/ 29 | /.nb-gradle/ 30 | build/ 31 | !**/src/main/**/build/ 32 | !**/src/test/**/build/ 33 | 34 | ### VS Code ### 35 | .vscode/ 36 | 37 | ### Mac OS ### 38 | .DS_Store -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/anotations/NotMonitoringParamsClass.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.anotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Annotation on the indications of class whose values must be masked during serialization. 10 | */ 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target({ElementType.TYPE}) 13 | public @interface NotMonitoringParamsClass { 14 | /** 15 | * A string that will be used to replace the field value during serialization. 16 | * The default is "*****". 17 | */ 18 | String value() default "*****"; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/anotations/NotMonitoringParamsField.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.anotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Annotation on the indications of fields whose values must be masked during serialization. 10 | */ 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target({ElementType.FIELD}) 13 | public @interface NotMonitoringParamsField { 14 | /** 15 | * A string that will be used to replace the field value during serialization. 16 | * The default is "*****". 17 | */ 18 | String value() default "*****"; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/utils/MessageTypeEnum.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.utils; 2 | 3 | public enum MessageTypeEnum { 4 | STAR, 5 | END, 6 | SQL_START, 7 | SQL_END, 8 | WEB_RESPONSE, 9 | WEB_REQUEST, 10 | CRITICAL_DB_ERROR, 11 | CRITICAL_KAFKA_ERROR, 12 | KAFKA_SEND, 13 | KAFKA_CONSUMER, 14 | 15 | STOMP_SEND, 16 | STOMP_CONSUMER, 17 | 18 | RAW_WS_CONSUMER, 19 | 20 | CASSANDRA_DB_START, 21 | CASSANDRA_DB_END, 22 | 23 | MONGO_DB_START, 24 | MONGO_DB_END, 25 | 26 | REDIS_DB_START, 27 | REDIS_DB_END, 28 | 29 | NEO4J_DB_START, 30 | NEO4J_DB_END, 31 | 32 | SOAP_START, 33 | SOAP_END, 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/utils/ContextCallableCustom.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.utils; 2 | 3 | import io.bitdive.parent.dto.TraceMethodContext; 4 | 5 | import java.util.concurrent.Callable; 6 | 7 | public class ContextCallableCustom implements Callable { 8 | private final Callable originalCallable; 9 | private final TraceMethodContext context; 10 | 11 | public ContextCallableCustom(Callable originalCallable, TraceMethodContext context) { 12 | this.originalCallable = originalCallable; 13 | this.context = context; 14 | } 15 | 16 | @Override 17 | public V call() throws Exception { 18 | ContextManager.setContextThread(context); 19 | return originalCallable.call(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/utils/objectMaperConfig/StreamPlaceholderSerializer.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.utils.objectMaperConfig; 2 | 3 | import com.fasterxml.jackson.core.JsonGenerator; 4 | import com.fasterxml.jackson.databind.SerializerProvider; 5 | import com.fasterxml.jackson.databind.ser.std.StdSerializer; 6 | 7 | import java.io.IOException; 8 | import java.util.stream.Stream; 9 | 10 | public final class StreamPlaceholderSerializer extends StdSerializer { 11 | 12 | public StreamPlaceholderSerializer() { 13 | super(Stream.class); // handledType = Stream.class 14 | } 15 | 16 | @Override 17 | public void serialize(Stream value, 18 | JsonGenerator gen, 19 | SerializerProvider provider) throws IOException { 20 | gen.writeString("[stream]"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/utils/ContextRunnableCustom.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.utils; 2 | 3 | import io.bitdive.parent.dto.TraceMethodContext; 4 | 5 | public class ContextRunnableCustom implements Runnable { 6 | private final Runnable originalRunnable; 7 | private final TraceMethodContext context; 8 | 9 | public ContextRunnableCustom(Runnable originalRunnable, TraceMethodContext context) { 10 | this.originalRunnable = originalRunnable; 11 | this.context = context; 12 | } 13 | 14 | @Override 15 | public void run() { 16 | TraceMethodContext oldContext = ContextManager.getContext(); 17 | try { 18 | ContextManager.setContextThread(context); 19 | originalRunnable.run(); 20 | } finally { 21 | ContextManager.setContextThread(oldContext); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/utils/MethodTypeEnum.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.utils; 2 | 3 | import lombok.Getter; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | @Getter 9 | public enum MethodTypeEnum { 10 | DB("Repository"), 11 | 12 | SCHEDULER("Scheduled"), 13 | 14 | WEB_GET("GetMapping"), 15 | WEB_POST("PostMapping"), 16 | WEB_PUT("PutMapping"), 17 | WEB_DELETE("DeleteMapping"), 18 | WEB_PATCH("PatchMapping"), 19 | METHOD(""); 20 | 21 | final String annotationName; 22 | 23 | MethodTypeEnum(String annotationName) { 24 | this.annotationName = annotationName; 25 | } 26 | 27 | public static List getListWebMethodType() { 28 | return Arrays.asList(WEB_GET, WEB_POST, WEB_PUT, WEB_DELETE, WEB_PATCH); 29 | } 30 | 31 | public static List getListMethodFlagInPoint() { 32 | return Arrays.asList(WEB_GET, WEB_POST, WEB_PUT, WEB_DELETE, WEB_PATCH, SCHEDULER); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-2.7/src/main/resources/META-INF/spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": [ 3 | { 4 | "name": "bitdive.monitoring.moduleName", 5 | "type": "java.lang.String", 6 | "description": "name module", 7 | "sourceType": "com.your.package.MonitoringProperties" 8 | }, 9 | { 10 | "name": "bitdive.monitoring.serviceName", 11 | "type": "java.lang.String", 12 | "description": "name service", 13 | "sourceType": "com.your.package.MonitoringProperties" 14 | }, 15 | { 16 | "name": "bitdive.monitoring.packedScanner", 17 | "type": "java.util.List", 18 | "description": "packed for scanner", 19 | "sourceType": "com.your.package.MonitoringProperties" 20 | }, 21 | { 22 | "name": "bitdive.monitoring.server-url", 23 | "type": "java.lang.String", 24 | "description": "URL server", 25 | "sourceType": "com.your.package.MonitoringProperties" 26 | }, 27 | { 28 | "name": "bitdive.monitoring.token", 29 | "type": "java.lang.String", 30 | "description": "token for authorization", 31 | "sourceType": "com.your.package.MonitoringProperties" 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/src/main/resources/META-INF/spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": [ 3 | { 4 | "name": "bitdive.monitoring.moduleName", 5 | "type": "java.lang.String", 6 | "description": "name module", 7 | "sourceType": "com.your.package.MonitoringProperties" 8 | }, 9 | { 10 | "name": "bitdive.monitoring.serviceName", 11 | "type": "java.lang.String", 12 | "description": "name service", 13 | "sourceType": "com.your.package.MonitoringProperties" 14 | }, 15 | { 16 | "name": "bitdive.monitoring.packedScanner", 17 | "type": "java.util.List", 18 | "description": "packed for scanner", 19 | "sourceType": "com.your.package.MonitoringProperties" 20 | }, 21 | { 22 | "name": "bitdive.monitoring.server-url", 23 | "type": "java.lang.String", 24 | "description": "URL server", 25 | "sourceType": "com.your.package.MonitoringProperties" 26 | }, 27 | { 28 | "name": "bitdive.monitoring.token", 29 | "type": "java.lang.String", 30 | "description": "token for authorization", 31 | "sourceType": "com.your.package.MonitoringProperties" 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/utils/objectMaperConfig/CollectionSizeLimiter.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.utils.objectMaperConfig; 2 | 3 | import com.fasterxml.jackson.databind.BeanDescription; 4 | import com.fasterxml.jackson.databind.JsonSerializer; 5 | import com.fasterxml.jackson.databind.SerializationConfig; 6 | import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; 7 | 8 | import java.util.Collection; 9 | 10 | public class CollectionSizeLimiter extends BeanSerializerModifier { 11 | private final int maxElements; 12 | private final String messageMaxElements; 13 | 14 | public CollectionSizeLimiter(int maxElements, String messageMaxElements) { 15 | this.maxElements = maxElements; 16 | this.messageMaxElements = messageMaxElements; 17 | } 18 | 19 | @Override 20 | public JsonSerializer modifySerializer(SerializationConfig config, 21 | BeanDescription beanDesc, 22 | JsonSerializer serializer) { 23 | if (Collection.class.isAssignableFrom(beanDesc.getBeanClass())) { 24 | return new LimitedCollectionSerializer(maxElements, messageMaxElements); 25 | } 26 | return serializer; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/dto/TraceMethodContext.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.dto; 2 | 3 | import com.github.f4b6a3.uuid.UuidCreator; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.concurrent.BlockingDeque; 10 | import java.util.concurrent.LinkedBlockingDeque; 11 | 12 | @Getter 13 | @Setter 14 | public class TraceMethodContext { 15 | public TraceMethodContext() { 16 | traceId = UuidCreator.getTimeBased().toString(); 17 | spanId = UuidCreator.getTimeBased().toString(); 18 | startMessageId = UuidCreator.getTimeBased().toString(); 19 | 20 | methodCallContextQueue = new LinkedBlockingDeque<>(); 21 | parentIdForRest = null; 22 | 23 | } 24 | private BlockingDeque methodCallContextQueue; 25 | private String traceId; 26 | private String spanId; 27 | 28 | private String serviceCallId; 29 | 30 | private String parentIdForRest; 31 | 32 | private String startMessageId; 33 | private String urlStart; 34 | 35 | 36 | private String classInpointName; 37 | private String methodInpointName; 38 | private String messageInpointId; 39 | 40 | // Incoming HTTP request capture (server side) 41 | private Map> requestHeaders; 42 | private byte[] requestBodyBytes; 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/utils/ByteBuddyConfigLoader.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.utils; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import io.bitdive.parent.parserConfig.ConfigForServiceDTO; 5 | import org.yaml.snakeyaml.Yaml; 6 | 7 | import java.io.InputStream; 8 | import java.util.Map; 9 | 10 | public class ByteBuddyConfigLoader { 11 | 12 | public static ConfigForServiceDTO load() { 13 | try { 14 | return readYaml(); 15 | } catch (Exception e) { 16 | return null; 17 | } 18 | } 19 | 20 | private static ConfigForServiceDTO readYaml() { 21 | try (InputStream in = ByteBuddyConfigLoader.class 22 | .getClassLoader() 23 | .getResourceAsStream("config-profiling-api.yml")) { 24 | 25 | if (in == null) { 26 | throw new IllegalStateException("Файл config-profiling-api.yml не найден"); 27 | } 28 | 29 | Yaml yaml = new Yaml(); 30 | Map root = yaml.load(in); 31 | 32 | Map monitoring = (Map) ((Map) root.get("bitdive")).get("monitoring"); 33 | 34 | ObjectMapper mapper = new ObjectMapper(); 35 | return mapper.convertValue(monitoring, ConfigForServiceDTO.class); 36 | 37 | } catch (Exception e) { 38 | throw new RuntimeException("Ошибка чтения YAML", e); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/utils/objectMaperConfig/LimitedCollectionSerializer.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.utils.objectMaperConfig; 2 | 3 | import com.fasterxml.jackson.core.JsonGenerator; 4 | import com.fasterxml.jackson.databind.JsonSerializer; 5 | import com.fasterxml.jackson.databind.SerializerProvider; 6 | 7 | import java.io.IOException; 8 | import java.util.Collection; 9 | 10 | public class LimitedCollectionSerializer extends JsonSerializer> { 11 | private final int maxElements; 12 | private final String messageMaxElements; 13 | 14 | public LimitedCollectionSerializer(int maxElements, String messageMaxElements) { 15 | this.maxElements = maxElements; 16 | this.messageMaxElements = messageMaxElements; 17 | } 18 | 19 | @Override 20 | public void serialize(Collection value, JsonGenerator gen, SerializerProvider serializers) throws IOException { 21 | gen.writeStartArray(); 22 | int count = 0; 23 | for (Object elem : value) { 24 | if (count < maxElements) { 25 | // Сериализуем элемент стандартным способом 26 | serializers.defaultSerializeValue(elem, gen); 27 | } else if (count == maxElements) { 28 | // Вместо следующих элементов записываем сообщение и выходим 29 | gen.writeString(this.messageMaxElements); 30 | break; 31 | } 32 | count++; 33 | } 34 | gen.writeEndArray(); 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/utils/hibernateConfig/HibernateModuleLoader.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.utils.hibernateConfig; 2 | 3 | import com.fasterxml.jackson.databind.Module; 4 | 5 | public class HibernateModuleLoader { 6 | public static Module registerHibernateModule() { 7 | try { 8 | Integer majorVersion = HibernateVersionDetector.getHibernateMajorVersion(); 9 | if (majorVersion == null) { 10 | return null; 11 | } 12 | 13 | if (loadTransientAnnotation(majorVersion) == null) { 14 | return null; 15 | } 16 | 17 | String moduleClassName = (majorVersion >= 6) 18 | ? "com.fasterxml.jackson.datatype.hibernate6.Hibernate6Module" 19 | : "com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module"; 20 | Class moduleClass = Class.forName(moduleClassName); 21 | return (com.fasterxml.jackson.databind.Module) moduleClass.getDeclaredConstructor().newInstance(); 22 | } catch (Exception e) { 23 | return null; 24 | } 25 | } 26 | 27 | public static Class loadTransientAnnotation(int hibernateMajorVersion) { 28 | String className = (hibernateMajorVersion >= 6) 29 | ? "jakarta.persistence.Transient" 30 | : "javax.persistence.Transient"; 31 | try { 32 | return Class.forName(className); 33 | } catch (ClassNotFoundException e) { 34 | return null; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-2.7/src/main/java/io/bitdive/jvm_metrics/MetricsCollector.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.jvm_metrics; 2 | 3 | import io.micrometer.core.instrument.Measurement; 4 | import io.micrometer.core.instrument.Meter; 5 | import io.micrometer.core.instrument.MeterRegistry; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | 9 | import java.time.OffsetDateTime; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | @Setter 14 | @Getter 15 | public class MetricsCollector { 16 | 17 | private String moduleName; 18 | private String serviceName; 19 | private OffsetDateTime createdMetric; 20 | private String serviceNodeUUID; 21 | private List listOfMetrics; 22 | 23 | public MetricsCollector(MeterRegistry meterRegistry) { 24 | listOfMetrics = collectMetrics(meterRegistry); 25 | } 26 | 27 | 28 | private List collectMetrics(MeterRegistry meterRegistry) { 29 | List metricsDtoList = new ArrayList<>(); 30 | for (Meter meter : meterRegistry.getMeters()) { 31 | MetricDto dto = new MetricDto(); 32 | 33 | dto.setName(meter.getId().getName()); 34 | 35 | for (Measurement measurement : meter.measure()) { 36 | String statistic = measurement.getStatistic().name(); 37 | double value = measurement.getValue(); 38 | dto.getMeasurements().add(new MeasurementDto(statistic, value)); 39 | } 40 | 41 | metricsDtoList.add(dto); 42 | } 43 | return metricsDtoList; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/src/main/java/io/bitdive/jvm_metrics/MetricsCollector.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.jvm_metrics; 2 | 3 | import io.micrometer.core.instrument.Measurement; 4 | import io.micrometer.core.instrument.Meter; 5 | import io.micrometer.core.instrument.MeterRegistry; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | 9 | import java.time.OffsetDateTime; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | @Setter 14 | @Getter 15 | public class MetricsCollector { 16 | 17 | private String moduleName; 18 | private String serviceName; 19 | private OffsetDateTime createdMetric; 20 | private String serviceNodeUUID; 21 | private List listOfMetrics; 22 | 23 | public MetricsCollector(MeterRegistry meterRegistry) { 24 | listOfMetrics = collectMetrics(meterRegistry); 25 | } 26 | 27 | 28 | private List collectMetrics(MeterRegistry meterRegistry) { 29 | List metricsDtoList = new ArrayList<>(); 30 | for (Meter meter : meterRegistry.getMeters()) { 31 | MetricDto dto = new MetricDto(); 32 | 33 | dto.setName(meter.getId().getName()); 34 | 35 | for (Measurement measurement : meter.measure()) { 36 | String statistic = measurement.getStatistic().name(); 37 | double value = measurement.getValue(); 38 | dto.getMeasurements().add(new MeasurementDto(statistic, value)); 39 | } 40 | 41 | metricsDtoList.add(dto); 42 | } 43 | return metricsDtoList; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/byte_buddy_agent/ByteBuddyAgentThreadCreator.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.byte_buddy_agent; 2 | 3 | import io.bitdive.parent.trasirovka.agent.utils.ContextManager; 4 | import io.bitdive.parent.trasirovka.agent.utils.ContextRunnableCustom; 5 | import net.bytebuddy.agent.builder.AgentBuilder; 6 | import net.bytebuddy.agent.builder.ResettableClassFileTransformer; 7 | import net.bytebuddy.asm.Advice; 8 | import net.bytebuddy.matcher.ElementMatchers; 9 | 10 | import java.lang.instrument.Instrumentation; 11 | import java.lang.reflect.Method; 12 | 13 | public class ByteBuddyAgentThreadCreator { 14 | public static ResettableClassFileTransformer init(Instrumentation instrumentation) { 15 | return new AgentBuilder.Default() 16 | .type(ElementMatchers.nameStartsWith("org.springframework.util.CustomizableThreadCreator")) // Укажите пакет ваших классов 17 | .transform((builder, typeDescription, classLoader, module, sd) -> 18 | builder.method(ElementMatchers.named("createThread")) // Выбор всех методов для обертки 19 | .intercept(Advice.to(ThreadCreatorInterceptor.class)) 20 | ).installOn(instrumentation); 21 | } 22 | 23 | public static class ThreadCreatorInterceptor { 24 | @Advice.OnMethodEnter 25 | public static void onMethodEnter(@Advice.Origin Method method, 26 | @Advice.Argument(value = 0, readOnly = false) Runnable runnable) { 27 | runnable = new ContextRunnableCustom(runnable, ContextManager.getContext()); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/utils/LoggerStatusContent.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.utils; 2 | 3 | 4 | import io.bitdive.parent.parserConfig.LogLevelEnum; 5 | import io.bitdive.parent.parserConfig.ProfilingConfig; 6 | import io.bitdive.parent.parserConfig.YamlParserConfig; 7 | 8 | import java.util.Arrays; 9 | import java.util.Optional; 10 | 11 | public class LoggerStatusContent { 12 | 13 | public static boolean getEnabledProfile() { 14 | return 15 | Optional.ofNullable(YamlParserConfig.getProfilingConfig()) 16 | .map(ProfilingConfig::getMonitoring) 17 | .map(monitoringConfig -> !monitoringConfig.isEnabled()) 18 | .orElse(true); 19 | } 20 | 21 | public static boolean isErrorsOrDebug(){ 22 | if (getEnabledProfile()) return false; 23 | return Arrays.asList(LogLevelEnum.ERRORS, LogLevelEnum.DEBUG).contains( 24 | Optional.ofNullable(YamlParserConfig.getProfilingConfig()) 25 | .map(ProfilingConfig::getMonitoring) 26 | .map(ProfilingConfig.MonitoringConfig::getLogLevel).orElse(LogLevelEnum.INFO) 27 | 28 | ); 29 | } 30 | 31 | public static boolean isErrors (){ 32 | if (getEnabledProfile()) return false; 33 | return YamlParserConfig.getProfilingConfig().getMonitoring().getLogLevel()==LogLevelEnum.ERRORS; 34 | } 35 | 36 | public static boolean isInfo (){ 37 | if (getEnabledProfile()) return false; 38 | return YamlParserConfig.getProfilingConfig().getMonitoring().getLogLevel()==LogLevelEnum.INFO; 39 | } 40 | public static boolean isDebug (){ 41 | if (getEnabledProfile()) return false; 42 | return YamlParserConfig.getProfilingConfig().getMonitoring().getLogLevel()==LogLevelEnum.DEBUG; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/byte_buddy_agent/ByteBuddyAgentThread.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.byte_buddy_agent; 2 | 3 | import io.bitdive.parent.dto.TraceMethodContext; 4 | import io.bitdive.parent.trasirovka.agent.utils.ContextCallableCustom; 5 | import io.bitdive.parent.trasirovka.agent.utils.ContextManager; 6 | import net.bytebuddy.agent.builder.AgentBuilder; 7 | import net.bytebuddy.agent.builder.ResettableClassFileTransformer; 8 | import net.bytebuddy.asm.Advice; 9 | import net.bytebuddy.matcher.ElementMatchers; 10 | 11 | import java.lang.instrument.Instrumentation; 12 | import java.util.concurrent.Callable; 13 | 14 | public class ByteBuddyAgentThread { 15 | public static ResettableClassFileTransformer init(Instrumentation instrumentation) { 16 | return new AgentBuilder.Default() 17 | .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) 18 | .with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE) 19 | .type(ElementMatchers.nameStartsWith("org.springframework.util.concurrent.FutureUtils")) 20 | .transform((builder, typeDescription, classLoader, module, sdf) -> 21 | builder.method(ElementMatchers.named("callAsync").and(ElementMatchers.takesArguments(2))) 22 | .intercept(Advice.to(ThreadInterceptor.class)) 23 | ).installOn(instrumentation); 24 | } 25 | 26 | public static class ThreadInterceptor { 27 | @Advice.OnMethodEnter 28 | public static void onEnter( 29 | @Advice.Origin String method, 30 | @Advice.Argument(value = 0, readOnly = false) Callable callable) { 31 | 32 | TraceMethodContext currentContext = ContextManager.getContext(); 33 | callable = new ContextCallableCustom<>(callable, currentContext); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/message_producer/PemUtils.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.message_producer; 2 | 3 | import lombok.SneakyThrows; 4 | import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; 5 | import org.bouncycastle.asn1.sec.ECPrivateKey; 6 | import org.bouncycastle.jce.provider.BouncyCastleProvider; 7 | import org.bouncycastle.openssl.PEMKeyPair; 8 | import org.bouncycastle.openssl.PEMParser; 9 | 10 | import java.io.StringReader; 11 | import java.security.KeyFactory; 12 | import java.security.PrivateKey; 13 | import java.security.Security; 14 | import java.security.spec.PKCS8EncodedKeySpec; 15 | 16 | public class PemUtils { 17 | @SneakyThrows 18 | public static PrivateKey getPrivateKeyFromPEM(String pem) { 19 | Security.addProvider(new BouncyCastleProvider()); 20 | PEMParser pemParser = new PEMParser(new StringReader(pem)); 21 | Object object = pemParser.readObject(); 22 | pemParser.close(); 23 | PrivateKeyInfo pkInfo; 24 | if (object instanceof PEMKeyPair) { 25 | pkInfo = ((PEMKeyPair) object).getPrivateKeyInfo(); 26 | } else if (object instanceof PrivateKeyInfo) { 27 | pkInfo = (PrivateKeyInfo) object; 28 | } else if (object instanceof ECPrivateKey) { 29 | ECPrivateKey ecPrivateKey = (ECPrivateKey) object; 30 | pkInfo = new PrivateKeyInfo(new org.bouncycastle.asn1.x509.AlgorithmIdentifier( 31 | org.bouncycastle.asn1.x9.X9ObjectIdentifiers.id_ecPublicKey), ecPrivateKey); 32 | } else { 33 | throw new IllegalArgumentException("Неподдерживаемый тип PEM-объекта: " + object.getClass().getName()); 34 | } 35 | 36 | byte[] pkcs8Bytes = pkInfo.getEncoded(); 37 | PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8Bytes); 38 | KeyFactory kf = KeyFactory.getInstance("EC", "BC"); 39 | return kf.generatePrivate(keySpec); 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/utils/objectMaperConfig/PackageBasedSerializerModifier.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.utils.objectMaperConfig; 2 | 3 | import com.fasterxml.jackson.core.JsonGenerator; 4 | import com.fasterxml.jackson.databind.BeanDescription; 5 | import com.fasterxml.jackson.databind.JsonSerializer; 6 | import com.fasterxml.jackson.databind.SerializationConfig; 7 | import com.fasterxml.jackson.databind.SerializerProvider; 8 | import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; 9 | 10 | import java.io.IOException; 11 | import java.util.Optional; 12 | 13 | public class PackageBasedSerializerModifier extends BeanSerializerModifier { 14 | 15 | private final String[] excludedPackages; 16 | 17 | public PackageBasedSerializerModifier(String... excludedPackages) { 18 | this.excludedPackages = excludedPackages; 19 | } 20 | 21 | @Override 22 | public JsonSerializer modifySerializer(SerializationConfig config, 23 | BeanDescription beanDesc, 24 | JsonSerializer serializer) { 25 | String packageName = 26 | Optional.ofNullable(beanDesc.getBeanClass()) 27 | .map(Class::getPackage) 28 | .map(Package::getName).orElse(null); 29 | 30 | if (packageName == null) { 31 | return serializer; 32 | } 33 | 34 | for (String excludedPackage : excludedPackages) { 35 | if (packageName.startsWith(excludedPackage)) { 36 | return new JsonSerializer() { 37 | @Override 38 | public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { 39 | gen.writeString("[excluded packages]"); 40 | } 41 | }; 42 | } 43 | } 44 | 45 | return serializer; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/parserConfig/DefaultMonitoringValues.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.parserConfig; 2 | 3 | public class DefaultMonitoringValues { 4 | 5 | public static ProfilingConfig.MonitoringConfig create() { 6 | ProfilingConfig.MonitoringConfig config = new ProfilingConfig.MonitoringConfig(); 7 | config.setLogLevel(LogLevelEnum.INFO); 8 | config.setMonitoringArgumentMethod(false); 9 | config.setMonitoringReturnMethod(false); 10 | config.setMonitoringStaticMethod(false); 11 | config.setMonitoringOnlySpringComponent(true); 12 | 13 | // dataFile 14 | ProfilingConfig.MonitoringConfig.MonitoringDataFile dataFile = new ProfilingConfig.MonitoringConfig.MonitoringDataFile(); 15 | dataFile.setPath("monitoringData"); 16 | dataFile.setTimerConvertForSend(10); 17 | dataFile.setFileStorageTime(30); 18 | config.setDataFile(dataFile); 19 | 20 | // sendFiles 21 | ProfilingConfig.MonitoringConfig.MonitoringSendFilesConfig sendFiles = new ProfilingConfig.MonitoringConfig.MonitoringSendFilesConfig(); 22 | sendFiles.setSchedulerTimer(1000L); 23 | ProfilingConfig.MonitoringConfig.MonitoringSendFilesConfig.ServerConsumerConfig serverConsumer = 24 | new ProfilingConfig.MonitoringConfig.MonitoringSendFilesConfig.ServerConsumerConfig(); 25 | serverConsumer.setUrl("http://localhost:8080"); 26 | sendFiles.setServerConsumer(serverConsumer); 27 | config.setSendFiles(sendFiles); 28 | 29 | // serialization 30 | ProfilingConfig.MonitoringConfig.Serialization serialization = new ProfilingConfig.MonitoringConfig.Serialization(); 31 | serialization.setExcludedPackages(new String[]{ 32 | "com.sun.", "sun.", "org.apache.", "com.zaxxer.", "jakarta.servlet.http.HttpServletResponse" 33 | }); 34 | serialization.setMaxElementCollection(500); 35 | config.setSerialization(serialization); 36 | 37 | return config; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/utils/objectMaperConfig/MaskingFilter.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.utils.objectMaperConfig; 2 | 3 | import com.fasterxml.jackson.core.JsonGenerator; 4 | import com.fasterxml.jackson.databind.BeanDescription; 5 | import com.fasterxml.jackson.databind.JsonSerializer; 6 | import com.fasterxml.jackson.databind.SerializationConfig; 7 | import com.fasterxml.jackson.databind.SerializerProvider; 8 | import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; 9 | import com.fasterxml.jackson.databind.ser.std.StdSerializer; 10 | 11 | import java.io.IOException; 12 | import java.util.Set; 13 | 14 | public class MaskingFilter extends BeanSerializerModifier { 15 | private final Set maskedFields; 16 | 17 | public MaskingFilter(Set maskedFields) { 18 | this.maskedFields = maskedFields; 19 | } 20 | 21 | @Override 22 | public JsonSerializer modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer serializer) { 23 | return new MaskingSerializer((JsonSerializer) serializer, maskedFields); 24 | } 25 | 26 | static class MaskingSerializer extends StdSerializer { 27 | private final JsonSerializer defaultSerializer; 28 | private final Set maskedFields; 29 | 30 | protected MaskingSerializer(JsonSerializer defaultSerializer, Set maskedFields) { 31 | super(Object.class); 32 | this.defaultSerializer = defaultSerializer; 33 | this.maskedFields = maskedFields; 34 | } 35 | 36 | @Override 37 | public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException { 38 | if (maskedFields.contains(gen.getOutputContext().getCurrentName())) { 39 | gen.writeString("****"); // Заменяем значение на "****" 40 | } else { 41 | defaultSerializer.serialize(value, gen, provider); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-2.7/src/main/java/io/bitdive/SpringConfigProfiling.java: -------------------------------------------------------------------------------- 1 | package io.bitdive; 2 | 3 | import io.bitdive.aspect.*; 4 | import org.springframework.beans.factory.annotation.Configurable; 5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Conditional; 8 | 9 | @Configurable 10 | public class SpringConfigProfiling { 11 | @Bean 12 | @ConditionalOnClass(name = "org.springframework.data.repository.Repository") 13 | @Conditional(YamlParserCondition.class) 14 | public RepositoryAspect repositoryInterceptor() { 15 | return new RepositoryAspect(); 16 | } 17 | 18 | @Bean 19 | @ConditionalOnClass(name = "org.springframework.cloud.openfeign.FeignClient") 20 | @Conditional(YamlParserCondition.class) 21 | public FeignClientAspect feignClientInterceptor() { 22 | 23 | return new FeignClientAspect(); 24 | } 25 | 26 | @Bean 27 | @ConditionalOnClass(name = "org.springframework.scheduling.annotation.Scheduled") 28 | @Conditional(YamlParserCondition.class) 29 | public SchedulerAspect schedulerAspect() { 30 | return new SchedulerAspect(); 31 | } 32 | 33 | @Bean 34 | @ConditionalOnClass(name = "org.springframework.kafka.annotation.KafkaListener") 35 | @Conditional(YamlParserCondition.class) 36 | public KafkaListenerAspect kafkaListenerAspect() { 37 | return new KafkaListenerAspect(); 38 | } 39 | 40 | @Bean 41 | @ConditionalOnClass(name = "org.springframework.messaging.handler.annotation.MessageMapping") 42 | @Conditional(YamlParserCondition.class) 43 | public StompMessageMappingAspect stompMessageMappingAspect() { 44 | return new StompMessageMappingAspect(); 45 | } 46 | 47 | @Bean 48 | @ConditionalOnClass(name = "org.springframework.messaging.handler.annotation.SendTo") 49 | @Conditional(YamlParserCondition.class) 50 | public StompSendToAspect stompSendToAspect() { 51 | return new StompSendToAspect(); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/src/main/java/io/bitdive/SpringConfigProfiling.java: -------------------------------------------------------------------------------- 1 | package io.bitdive; 2 | 3 | import io.bitdive.aspect.*; 4 | import org.springframework.beans.factory.annotation.Configurable; 5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Conditional; 8 | 9 | @Configurable 10 | public class SpringConfigProfiling { 11 | 12 | @Bean 13 | @ConditionalOnClass(name = "org.springframework.data.repository.Repository") 14 | @Conditional(YamlParserCondition.class) 15 | public RepositoryAspect repositoryInterceptor() { 16 | return new RepositoryAspect(); 17 | } 18 | 19 | @Bean 20 | @ConditionalOnClass(name = "org.springframework.cloud.openfeign.FeignClient") 21 | @Conditional(YamlParserCondition.class) 22 | public FeignClientAspect feignClientInterceptor() { 23 | return new FeignClientAspect(); 24 | } 25 | 26 | @Bean 27 | @ConditionalOnClass(name = "org.springframework.scheduling.annotation.Scheduled") 28 | @Conditional(YamlParserCondition.class) 29 | public SchedulerAspect schedulerAspect() { 30 | return new SchedulerAspect(); 31 | } 32 | 33 | @Bean 34 | @ConditionalOnClass(name = "org.springframework.kafka.annotation.KafkaListener") 35 | @Conditional(YamlParserCondition.class) 36 | public KafkaListenerAspect kafkaListenerAspect() { 37 | return new KafkaListenerAspect(); 38 | } 39 | 40 | @Bean 41 | @ConditionalOnClass(name = "org.springframework.messaging.handler.annotation.MessageMapping") 42 | @Conditional(YamlParserCondition.class) 43 | public StompMessageMappingAspect stompMessageMappingAspect() { 44 | return new StompMessageMappingAspect(); 45 | } 46 | 47 | @Bean 48 | @ConditionalOnClass(name = "org.springframework.messaging.handler.annotation.SendTo") 49 | @Conditional(YamlParserCondition.class) 50 | public StompSendToAspect stompSendToAspect() { 51 | return new StompSendToAspect(); 52 | } 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/utils/objectMaperConfig/FlowDataToPlaceholderModule.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.utils.objectMaperConfig; 2 | 3 | import com.fasterxml.jackson.core.JsonGenerator; 4 | import com.fasterxml.jackson.databind.JsonSerializer; 5 | import com.fasterxml.jackson.databind.SerializerProvider; 6 | import com.fasterxml.jackson.databind.module.SimpleModule; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.io.Reader; 11 | import java.nio.ByteBuffer; 12 | import java.sql.Blob; 13 | import java.sql.Clob; 14 | import java.util.stream.*; 15 | 16 | public class FlowDataToPlaceholderModule extends SimpleModule { 17 | public FlowDataToPlaceholderModule() { 18 | 19 | 20 | addSerializer(byte[].class, new PlaceholderSerializer<>("[byte arrays]")); 21 | 22 | addSerializer(InputStream.class, new PlaceholderSerializer<>("[inputStream]")); 23 | addSerializer(Reader.class, new PlaceholderSerializer<>("[reader]")); 24 | addSerializer(ByteBuffer.class, new PlaceholderSerializer<>("[byteBuffer]")); 25 | 26 | addSerializer(IntStream.class, new PlaceholderSerializer<>("[int-stream]")); 27 | addSerializer(LongStream.class, new PlaceholderSerializer<>("[long-stream]")); 28 | addSerializer(DoubleStream.class, new PlaceholderSerializer<>("[double-stream]")); 29 | addSerializer(BaseStream.class, new PlaceholderSerializer<>("[stream]")); 30 | addSerializer(Stream.class, new PlaceholderSerializer<>("[stream]")); 31 | 32 | addSerializer(Blob.class, new PlaceholderSerializer<>("[blob]")); 33 | addSerializer(Clob.class, new PlaceholderSerializer<>("[clob]")); 34 | } 35 | 36 | private static final class PlaceholderSerializer extends JsonSerializer { 37 | private final String marker; 38 | 39 | PlaceholderSerializer(String marker) { 40 | this.marker = marker; 41 | } 42 | 43 | @Override 44 | public void serialize(T value, JsonGenerator gen, SerializerProvider prov) throws IOException { 45 | gen.writeString(marker); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-2.7/src/main/java/io/bitdive/jvm_metrics/MetricsService.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.jvm_metrics; 2 | 3 | 4 | import com.google.gson.Gson; 5 | import com.google.gson.GsonBuilder; 6 | import com.google.gson.JsonDeserializer; 7 | import com.google.gson.JsonSerializer; 8 | import io.bitdive.parent.parserConfig.YamlParserConfig; 9 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 10 | import io.micrometer.core.instrument.MeterRegistry; 11 | 12 | import java.time.OffsetDateTime; 13 | import java.time.format.DateTimeFormatter; 14 | 15 | public class MetricsService { 16 | private MetricsCollector metricsCollector; 17 | private static final Gson mapper = new GsonBuilder() 18 | .registerTypeAdapter(OffsetDateTime.class, (JsonSerializer) (src, typeOfSrc, context) -> 19 | context.serialize(src.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME))) 20 | .registerTypeAdapter(OffsetDateTime.class, (JsonDeserializer) (json, type, context) -> 21 | OffsetDateTime.parse(json.getAsString(), DateTimeFormatter.ISO_OFFSET_DATE_TIME)) 22 | .create(); 23 | 24 | 25 | public MetricsService(MeterRegistry meterRegistry) { 26 | try { 27 | metricsCollector = new MetricsCollector(meterRegistry); 28 | metricsCollector.setModuleName(YamlParserConfig.getProfilingConfig().getApplication().getModuleName()); 29 | metricsCollector.setServiceName(YamlParserConfig.getProfilingConfig().getApplication().getServiceName()); 30 | metricsCollector.setCreatedMetric(OffsetDateTime.now()); 31 | metricsCollector.setServiceNodeUUID(YamlParserConfig.getUUIDService()); 32 | } catch (Exception e) { 33 | if (LoggerStatusContent.isErrorsOrDebug()) 34 | System.err.println("Failed to write metrics to file: " + e.getMessage()); 35 | } 36 | } 37 | 38 | 39 | public String sendMetrics() { 40 | try { 41 | return mapper.toJson(metricsCollector); 42 | } catch (Exception e) { 43 | System.out.println("Error while sending metrics: " + e.getMessage()); 44 | } 45 | return ""; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/src/main/java/io/bitdive/jvm_metrics/MetricsService.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.jvm_metrics; 2 | 3 | 4 | import com.google.gson.Gson; 5 | import com.google.gson.GsonBuilder; 6 | import com.google.gson.JsonDeserializer; 7 | import com.google.gson.JsonSerializer; 8 | import io.bitdive.parent.parserConfig.YamlParserConfig; 9 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 10 | import io.micrometer.core.instrument.MeterRegistry; 11 | 12 | import java.time.OffsetDateTime; 13 | import java.time.format.DateTimeFormatter; 14 | 15 | public class MetricsService { 16 | private MetricsCollector metricsCollector; 17 | private static final Gson mapper = new GsonBuilder() 18 | .registerTypeAdapter(OffsetDateTime.class, (JsonSerializer) (src, typeOfSrc, context) -> 19 | context.serialize(src.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME))) 20 | .registerTypeAdapter(OffsetDateTime.class, (JsonDeserializer) (json, type, context) -> 21 | OffsetDateTime.parse(json.getAsString(), DateTimeFormatter.ISO_OFFSET_DATE_TIME)) 22 | .create(); 23 | 24 | 25 | public MetricsService(MeterRegistry meterRegistry) { 26 | try { 27 | metricsCollector = new MetricsCollector(meterRegistry); 28 | metricsCollector.setModuleName(YamlParserConfig.getProfilingConfig().getApplication().getModuleName()); 29 | metricsCollector.setServiceName(YamlParserConfig.getProfilingConfig().getApplication().getServiceName()); 30 | metricsCollector.setCreatedMetric(OffsetDateTime.now()); 31 | metricsCollector.setServiceNodeUUID(YamlParserConfig.getUUIDService()); 32 | } catch (Exception e) { 33 | if (LoggerStatusContent.isErrorsOrDebug()) 34 | System.err.println("Failed to write metrics to file: " + e.getMessage()); 35 | } 36 | } 37 | 38 | 39 | public String sendMetrics() { 40 | try { 41 | return mapper.toJson(metricsCollector); 42 | } catch (Exception e) { 43 | System.out.println("Error while sending metrics: " + e.getMessage()); 44 | } 45 | return ""; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/init/MonitoringStarting.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.init; 2 | 3 | 4 | import io.bitdive.parent.safety_config.VaultGettingConfig; 5 | import io.bitdive.parent.trasirovka.agent.byte_buddy_agent.*; 6 | import io.bitdive.parent.trasirovka.agent.byte_buddy_agent.db.*; 7 | import io.bitdive.parent.trasirovka.agent.byte_buddy_agent.db.cached.ByteBuddyCachedOpenSearchReqest; 8 | import io.bitdive.parent.trasirovka.agent.byte_buddy_agent.db.cached.ByteBuddyCachedOpenSearchResponse; 9 | import net.bytebuddy.agent.ByteBuddyAgent; 10 | 11 | import java.lang.instrument.Instrumentation; 12 | 13 | public class MonitoringStarting { 14 | public static void init() { 15 | VaultGettingConfig.initVaultConnect(); 16 | Instrumentation instrumentation = ByteBuddyAgent.install(); 17 | 18 | ByteBuddyAgentBasic.init(instrumentation); 19 | ByteBuddyAgentThread.init(instrumentation); 20 | ByteBuddyAgentThreadCreator.init(instrumentation); 21 | ByteBuddySimpleClientHttpResponse.init(instrumentation); 22 | ByteBuddyAgentRestTemplateRequestWeb.init(instrumentation); 23 | ByteBuddyAgentCoyoteInputStream.init(instrumentation); // Captures raw body bytes 24 | ByteBuddyAgentResponseWeb.init(instrumentation); 25 | ByteBuddyAgentSql.init(instrumentation); 26 | ByteBuddyAgentCatalinaResponse.init(instrumentation); 27 | ByteBuddyAgentFeignRequestWeb.init(instrumentation); 28 | ByteBuddyAgentSqlDriver.init(instrumentation); 29 | ByteBuddyAgentKafkaSend.init(instrumentation); 30 | ByteBuddyAgentKafkaInterceptor.init(instrumentation); 31 | KafkaConsumerAgent.init(instrumentation); 32 | 33 | ByteBuddyAgentCassandra.init(instrumentation); 34 | ByteBuddyAgentMongoDelegate.init(instrumentation); 35 | ByteBuddyAgentRedis.init(instrumentation); 36 | ByteBuddyAgentNeo4j.init(instrumentation); 37 | 38 | ByteBuddyAgentOpenSearch.init(instrumentation); 39 | ByteBuddyCachedOpenSearchResponse.init(instrumentation); 40 | ByteBuddyCachedOpenSearchReqest.init(instrumentation); 41 | 42 | ByteBuddyAgentSoap.init(instrumentation); 43 | 44 | ByteBuddyAgentSpringRawWs.init(instrumentation); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/byte_buddy_agent/db/ByteBuddyAgentSqlDriver.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.byte_buddy_agent.db; 2 | 3 | import io.bitdive.parent.parserConfig.YamlParserConfig; 4 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 5 | import net.bytebuddy.agent.builder.AgentBuilder; 6 | import net.bytebuddy.agent.builder.ResettableClassFileTransformer; 7 | import net.bytebuddy.implementation.MethodDelegation; 8 | import net.bytebuddy.implementation.bind.annotation.*; 9 | import net.bytebuddy.matcher.ElementMatchers; 10 | 11 | import java.lang.instrument.Instrumentation; 12 | import java.lang.reflect.Method; 13 | import java.sql.Driver; 14 | import java.util.concurrent.Callable; 15 | 16 | import static io.bitdive.parent.message_producer.MessageService.sendMessageCriticalDBError; 17 | 18 | public class ByteBuddyAgentSqlDriver { 19 | 20 | public static ResettableClassFileTransformer init(Instrumentation instrumentation) { 21 | return new AgentBuilder.Default() 22 | .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) 23 | .type(ElementMatchers.isSubTypeOf(Driver.class)) 24 | .transform((builder, typeDescription, classLoader, module, protectionDomain) -> 25 | builder.method(ElementMatchers.named("connect")) 26 | .intercept(MethodDelegation.to(DriverInterceptor.class)) 27 | ) 28 | .installOn(instrumentation); 29 | } 30 | 31 | public static class DriverInterceptor { 32 | 33 | @RuntimeType 34 | public static Object intercept(@Origin Method method, 35 | @SuperCall Callable zuper, 36 | @This Object thiz, 37 | @AllArguments Object[] args) throws Throwable { 38 | String url = (args[0] instanceof String) ? (String) args[0] : null; 39 | // Properties info = (args[1] instanceof Properties) ? (Properties) args[1] : null; 40 | 41 | if (LoggerStatusContent.getEnabledProfile()) return zuper.call(); 42 | try { 43 | return zuper.call(); 44 | } catch (Exception t) { 45 | sendMessageCriticalDBError(url, t.getMessage()); 46 | throw t; 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/utils/SQLUtils.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.utils; 2 | 3 | import org.apache.commons.lang3.ObjectUtils; 4 | 5 | import java.sql.CallableStatement; 6 | import java.sql.Connection; 7 | import java.sql.PreparedStatement; 8 | import java.sql.Statement; 9 | import java.util.regex.Matcher; 10 | import java.util.regex.Pattern; 11 | 12 | public class SQLUtils { 13 | 14 | public static String getSQLFromStatement(Object stmt) { 15 | if (stmt == null) { 16 | return ""; 17 | } 18 | 19 | 20 | if (stmt instanceof CallableStatement) { 21 | 22 | return getCallableStatement(stmt); 23 | } 24 | 25 | // Если ни один из вышеуказанных вариантов не сработал, применяем стандартное извлечение SQL из строки. 26 | return extractSQL(stmt.toString()); 27 | } 28 | 29 | public static String getCallableStatement(Object stmt) { 30 | return CallableStatementParser.getCallableSQL((CallableStatement) stmt); 31 | } 32 | 33 | 34 | public static String extractSQL(String input) { 35 | Pattern pattern = Pattern.compile("(?i)\\b(select|update|insert|delete|with)\\b"); 36 | Matcher matcher = pattern.matcher(input); 37 | 38 | if (matcher.find()) { 39 | return input.substring(matcher.start()); 40 | } 41 | return input; 42 | } 43 | 44 | public static String getConnectionUrlFromStatement(Object stmt) { 45 | String connectionUrl = getConnectionUrl(stmt); 46 | if (!ObjectUtils.isEmpty(connectionUrl)) { 47 | connectionUrl = connectionUrl.split(";", -1)[0]; 48 | } 49 | return connectionUrl; 50 | } 51 | 52 | private static String getConnectionUrl(Object stmt) { 53 | try { 54 | Connection connection = null; 55 | if (stmt instanceof PreparedStatement) { 56 | connection = ((PreparedStatement) stmt).getConnection(); 57 | } else if (stmt instanceof Statement) { 58 | connection = ((Statement) stmt).getConnection(); 59 | } 60 | if (connection != null) { 61 | return connection.getMetaData().getURL(); 62 | } 63 | } catch (Exception e) { 64 | System.err.println("Error extracting connection URL: " + e.getMessage()); 65 | } 66 | return null; 67 | } 68 | } 69 | 70 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/byte_buddy_agent/KafkaConsumerAgent.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.byte_buddy_agent; 2 | 3 | import io.bitdive.parent.parserConfig.YamlParserConfig; 4 | import io.bitdive.parent.trasirovka.agent.utils.KafkaAgentStorage; 5 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 6 | import net.bytebuddy.agent.builder.AgentBuilder; 7 | import net.bytebuddy.agent.builder.ResettableClassFileTransformer; 8 | import net.bytebuddy.asm.Advice; 9 | import net.bytebuddy.matcher.ElementMatchers; 10 | 11 | import java.lang.instrument.Instrumentation; 12 | import java.util.Map; 13 | import java.util.Optional; 14 | 15 | public class KafkaConsumerAgent { 16 | public static ResettableClassFileTransformer init(Instrumentation instrumentation) { 17 | return new AgentBuilder.Default() 18 | .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) 19 | .type(ElementMatchers.named("org.apache.kafka.clients.consumer.KafkaConsumer")) 20 | .transform((builder, typeDescription, classLoader, module, dd) -> 21 | builder.constructor(ElementMatchers.any() 22 | /* ElementMatchers.takesArguments(1) 23 | .and(ElementMatchers.takesArgument(0, Map.class))*/ 24 | ) 25 | .intercept(Advice.to(KafkaConsumerConstructorAdvice.class)) 26 | ) 27 | .installOn(instrumentation); 28 | } 29 | 30 | public static class KafkaConsumerConstructorAdvice { 31 | @Advice.OnMethodEnter 32 | public static void onEnter(@Advice.AllArguments Object[] allArgs) { 33 | if (LoggerStatusContent.getEnabledProfile()) return; 34 | try { 35 | Object bootstrapServers = null; 36 | if (allArgs.length > 0) { 37 | Object arg0 = allArgs[0]; 38 | if (arg0 instanceof Map) { 39 | Map configs = (Map) arg0; 40 | bootstrapServers = configs.get("bootstrap.servers"); 41 | KafkaAgentStorage.KAFKA_BOOTSTRAP_CONSUMER_STRING = 42 | Optional.ofNullable(bootstrapServers) 43 | .map(Object::toString) 44 | .orElse(""); 45 | } 46 | } 47 | } catch (Exception e) { 48 | System.err.println("ByteBuddyAgentKafkaInterceptor ERROR: " + e.getMessage()); 49 | } 50 | } 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/byte_buddy_agent/ByteBuddyAgentCoyoteInputStream.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.byte_buddy_agent; 2 | 3 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 4 | import io.bitdive.parent.trasirovka.agent.utils.RequestBodyCollector; 5 | import net.bytebuddy.agent.builder.AgentBuilder; 6 | import net.bytebuddy.agent.builder.ResettableClassFileTransformer; 7 | import net.bytebuddy.asm.Advice; 8 | import net.bytebuddy.matcher.ElementMatchers; 9 | 10 | import java.lang.instrument.Instrumentation; 11 | 12 | public class ByteBuddyAgentCoyoteInputStream { 13 | 14 | public static ResettableClassFileTransformer init(Instrumentation instrumentation) { 15 | try { 16 | return new AgentBuilder.Default() 17 | .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) 18 | .type(ElementMatchers.named("org.apache.catalina.connector.CoyoteInputStream")) 19 | .transform((builder, typeDescription, classLoader, module, dd) -> 20 | builder 21 | .visit(Advice.to(ReadIntAdvice.class).on( 22 | ElementMatchers.named("read").and(ElementMatchers.takesNoArguments()) 23 | )) 24 | .visit(Advice.to(ReadBytesAdvice.class).on( 25 | ElementMatchers.named("read").and(ElementMatchers.takesArguments(3)) 26 | )) 27 | ) 28 | .installOn(instrumentation); 29 | } catch (Exception e) { 30 | if (LoggerStatusContent.isErrorsOrDebug()) { 31 | System.err.println("ByteBuddyAgentCoyoteInputStream init error: " + e.getMessage()); 32 | } 33 | } 34 | return null; 35 | } 36 | 37 | public static class ReadIntAdvice { 38 | @Advice.OnMethodExit(onThrowable = Throwable.class) 39 | public static void onExit(@Advice.Return int result) { 40 | if (result >= 0) { 41 | RequestBodyCollector.append((byte) result); 42 | } 43 | } 44 | } 45 | 46 | public static class ReadBytesAdvice { 47 | @Advice.OnMethodExit(onThrowable = Throwable.class) 48 | public static void onExit(@Advice.Argument(0) byte[] b, 49 | @Advice.Argument(1) int off, 50 | @Advice.Argument(2) int len, 51 | @Advice.Return int result) { 52 | if (result > 0 && b != null) { 53 | RequestBodyCollector.append(b, off, result); 54 | } 55 | } 56 | } 57 | } 58 | 59 | 60 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/message_producer/LocalCryptoService.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.message_producer; 2 | 3 | import io.bitdive.parent.utils.Pair; 4 | 5 | import javax.crypto.Cipher; 6 | import javax.crypto.SecretKey; 7 | import javax.crypto.spec.IvParameterSpec; 8 | import javax.crypto.spec.SecretKeySpec; 9 | import java.nio.charset.StandardCharsets; 10 | import java.security.PrivateKey; 11 | import java.security.Signature; 12 | import java.util.Base64; 13 | 14 | 15 | public class LocalCryptoService { 16 | 17 | private static final String ENCRYPTION_ALGORITHM = "AES/CBC/PKCS5Padding"; 18 | private static final int IV_LENGTH = 16; 19 | 20 | private static volatile Pair pairSecretKey = new Pair<>(-1, null); 21 | private static volatile Pair pairPrivateKey = new Pair<>(-1, null); 22 | 23 | private static final java.security.SecureRandom secureRandom = new java.security.SecureRandom(); 24 | 25 | public static void addKeySecretKey(Integer keyId, String keyBase64) { 26 | if (!keyId.equals(pairSecretKey.getKey())) { 27 | byte[] decodedKey = Base64.getDecoder().decode(keyBase64); 28 | pairSecretKey = Pair.createPair(keyId, new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES")); 29 | } 30 | } 31 | 32 | public static void addKeyPrivateKey(Integer keyId, String rsaPrivateKey) { 33 | if (!keyId.equals(pairPrivateKey.getKey())) { 34 | pairPrivateKey = Pair.createPair(keyId, PemUtils.getPrivateKeyFromPEM(rsaPrivateKey)); 35 | } 36 | } 37 | 38 | public static Pair encrypt(String plainText) throws Exception { 39 | if (pairSecretKey.getVal() == null) { 40 | Thread.sleep(1000); 41 | } 42 | Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM); 43 | byte[] iv = new byte[IV_LENGTH]; 44 | secureRandom.nextBytes(iv); 45 | 46 | IvParameterSpec ivSpec = new IvParameterSpec(iv); 47 | cipher.init(Cipher.ENCRYPT_MODE, pairSecretKey.getVal(), ivSpec); 48 | 49 | byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); 50 | byte[] combined = new byte[iv.length + encryptedBytes.length]; 51 | System.arraycopy(iv, 0, combined, 0, iv.length); 52 | System.arraycopy(encryptedBytes, 0, combined, iv.length, encryptedBytes.length); 53 | 54 | return Pair.createPair(pairSecretKey.getKey(), Base64.getEncoder().encodeToString(combined)); 55 | } 56 | 57 | public static Pair sign(byte[] encryptedData) throws Exception { 58 | if (pairPrivateKey.getVal() == null) { 59 | Thread.sleep(1000); 60 | } 61 | Signature signature = Signature.getInstance("SHA256withECDSA"); 62 | signature.initSign(pairPrivateKey.getVal()); 63 | signature.update(encryptedData); 64 | return Pair.createPair(pairPrivateKey.getKey(), signature.sign()); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/src/main/java/io/bitdive/aspect/FeignClientAspect.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.aspect; 2 | 3 | import com.github.f4b6a3.uuid.UuidCreator; 4 | import io.bitdive.parent.trasirovka.agent.utils.ContextManager; 5 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 6 | import io.bitdive.parent.trasirovka.agent.utils.ReflectionUtils; 7 | import io.bitdive.parent.utils.MethodTypeEnum; 8 | import org.aspectj.lang.ProceedingJoinPoint; 9 | import org.aspectj.lang.annotation.Around; 10 | import org.aspectj.lang.annotation.Aspect; 11 | import org.aspectj.lang.reflect.MethodSignature; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.time.OffsetDateTime; 15 | 16 | import static io.bitdive.parent.message_producer.MessageService.sendMessageEnd; 17 | import static io.bitdive.parent.message_producer.MessageService.sendMessageStart; 18 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.*; 19 | 20 | @Aspect 21 | @Component 22 | public class FeignClientAspect { 23 | 24 | @Around("@within(org.springframework.cloud.openfeign.FeignClient)") 25 | public Object aroundFeignClientMethods(ProceedingJoinPoint joinPoint) throws Throwable { 26 | if (LoggerStatusContent.getEnabledProfile()) return joinPoint.proceed(); 27 | String UUIDMessage = UuidCreator.getTimeBased().toString(); 28 | Object retVal = null; 29 | Throwable thrown = null; 30 | MethodSignature methodSig = (MethodSignature) joinPoint.getSignature(); 31 | 32 | try { 33 | 34 | sendMessageStart( 35 | UUIDMessage, 36 | methodSig.getDeclaringTypeName(), 37 | methodSig.getName(), 38 | ContextManager.getTraceId(), 39 | ContextManager.getSpanId(), 40 | OffsetDateTime.now(), 41 | ContextManager.getParentIdMessageIdQueue(), 42 | false, 43 | ReflectionUtils.objectToString(paramConvert(joinPoint.getArgs(), methodSig.getMethod())), 44 | MethodTypeEnum.METHOD.toString(), 45 | "", 46 | "", 47 | ContextManager.getMethodInpointName(), 48 | ContextManager.getMessageInpointId(), 49 | ContextManager.getClassInpointName() 50 | ); 51 | 52 | 53 | ContextManager.setMethodCallContextQueue(UUIDMessage); 54 | 55 | retVal = joinPoint.proceed(); 56 | 57 | } catch (Throwable t) { 58 | thrown = t; 59 | throw t; 60 | } finally { 61 | 62 | sendMessageEnd( 63 | UUIDMessage, 64 | OffsetDateTime.now(), 65 | getaNullThrowable(thrown), 66 | ReflectionUtils.objectToString(methodReturnConvert(retVal)), 67 | ContextManager.getTraceId(), 68 | ContextManager.getSpanId() 69 | ); 70 | 71 | 72 | ContextManager.removeLastQueue(); 73 | } 74 | 75 | return retVal; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-2.7/src/main/java/io/bitdive/aspect/FeignClientAspect.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.aspect; 2 | 3 | import com.github.f4b6a3.uuid.UuidCreator; 4 | import io.bitdive.parent.trasirovka.agent.utils.ContextManager; 5 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 6 | import io.bitdive.parent.trasirovka.agent.utils.ReflectionUtils; 7 | import io.bitdive.parent.utils.MethodTypeEnum; 8 | import org.aspectj.lang.ProceedingJoinPoint; 9 | import org.aspectj.lang.annotation.Around; 10 | import org.aspectj.lang.annotation.Aspect; 11 | import org.aspectj.lang.reflect.MethodSignature; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.time.OffsetDateTime; 15 | 16 | import static io.bitdive.parent.message_producer.MessageService.sendMessageEnd; 17 | import static io.bitdive.parent.message_producer.MessageService.sendMessageStart; 18 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.*; 19 | 20 | @Aspect 21 | @Component 22 | public class FeignClientAspect { 23 | 24 | @Around("@within(org.springframework.cloud.openfeign.FeignClient)") 25 | public Object aroundFeignClientMethods(ProceedingJoinPoint joinPoint) throws Throwable { 26 | if (LoggerStatusContent.getEnabledProfile()) return joinPoint.proceed(); 27 | String UUIDMessage = UuidCreator.getTimeBased().toString(); 28 | Object retVal = null; 29 | Throwable thrown = null; 30 | MethodSignature methodSig = (MethodSignature) joinPoint.getSignature(); 31 | 32 | try { 33 | 34 | sendMessageStart( 35 | UUIDMessage, 36 | methodSig.getDeclaringTypeName(), 37 | methodSig.getName(), 38 | ContextManager.getTraceId(), 39 | ContextManager.getSpanId(), 40 | OffsetDateTime.now(), 41 | ContextManager.getParentIdMessageIdQueue(), 42 | false, 43 | ReflectionUtils.objectToString(paramConvert(joinPoint.getArgs(), methodSig.getMethod())), 44 | MethodTypeEnum.METHOD.toString(), 45 | "", 46 | "", 47 | ContextManager.getMethodInpointName(), 48 | ContextManager.getMessageInpointId(), 49 | ContextManager.getClassInpointName() 50 | ); 51 | 52 | 53 | ContextManager.setMethodCallContextQueue(UUIDMessage); 54 | 55 | retVal = joinPoint.proceed(); 56 | 57 | } catch (Throwable t) { 58 | thrown = t; 59 | throw t; 60 | } finally { 61 | 62 | sendMessageEnd( 63 | UUIDMessage, 64 | OffsetDateTime.now(), 65 | getaNullThrowable(thrown), 66 | ReflectionUtils.objectToString(methodReturnConvert(retVal)), 67 | ContextManager.getTraceId(), 68 | ContextManager.getSpanId() 69 | ); 70 | 71 | 72 | ContextManager.removeLastQueue(); 73 | } 74 | 75 | return retVal; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/message_producer/HttpURLConnectionCustom.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.message_producer; 2 | 3 | import io.bitdive.parent.utils.Pair; 4 | 5 | import java.io.*; 6 | import java.net.HttpURLConnection; 7 | import java.nio.charset.StandardCharsets; 8 | import java.nio.file.Files; 9 | 10 | public class HttpURLConnectionCustom { 11 | private static final String boundary = "*****" + System.currentTimeMillis() + "*****"; 12 | 13 | public static int sentToServer(HttpURLConnection connection, File file, Pair encryptedData, Pair signature) throws IOException { 14 | connection.setRequestMethod("POST"); 15 | connection.setDoOutput(true); 16 | connection.setDoInput(true); 17 | connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); 18 | connection.setRequestProperty("User-Agent", "Java client"); 19 | connection.setRequestProperty("Accept", "*/*"); 20 | 21 | try (OutputStream outputStream = connection.getOutputStream(); 22 | PrintWriter writer = new PrintWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8), true)) { 23 | 24 | String LINE_FEED = "\r\n"; 25 | writer.append("--").append(boundary).append(LINE_FEED); 26 | writer.append("Content-Disposition: form-data; name=\"encryptedData\"; filename=\"").append(file.getName()).append("\"").append(LINE_FEED); 27 | writer.append("Content-Type: ").append(Files.probeContentType(file.toPath())).append(LINE_FEED); 28 | writer.append(LINE_FEED).flush(); 29 | 30 | outputStream.write(encryptedData.getVal().getBytes(StandardCharsets.UTF_8)); 31 | outputStream.flush(); 32 | writer.append(LINE_FEED).flush(); 33 | 34 | 35 | writer.append("--").append(boundary).append(LINE_FEED); 36 | writer.append("Content-Disposition: form-data; name=\"signature\"").append(LINE_FEED); 37 | writer.append("Content-Type: text/plain").append(LINE_FEED); 38 | writer.append(LINE_FEED).flush(); 39 | writer.append(signature.getVal()).append(LINE_FEED).flush(); 40 | 41 | writer.append("--").append(boundary).append(LINE_FEED); 42 | writer.append("Content-Disposition: form-data; name=\"encrypteKeyId\"").append(LINE_FEED); 43 | writer.append("Content-Type: text/plain").append(LINE_FEED); 44 | writer.append(LINE_FEED).flush(); 45 | writer.append(encryptedData.getKey().toString()).append(LINE_FEED).flush(); 46 | 47 | writer.append("--").append(boundary).append(LINE_FEED); 48 | writer.append("Content-Disposition: form-data; name=\"signatureKeyId\"").append(LINE_FEED); 49 | writer.append("Content-Type: text/plain").append(LINE_FEED); 50 | writer.append(LINE_FEED).flush(); 51 | writer.append(signature.getKey().toString()).append(LINE_FEED).flush(); 52 | 53 | writer.append("--").append(boundary).append("--").append(LINE_FEED).flush(); 54 | 55 | } 56 | return connection.getResponseCode(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/src/main/java/io/bitdive/aspect/RepositoryAspect.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.aspect; 2 | 3 | import com.github.f4b6a3.uuid.UuidCreator; 4 | import io.bitdive.parent.trasirovka.agent.utils.ContextManager; 5 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 6 | import io.bitdive.parent.trasirovka.agent.utils.ReflectionUtils; 7 | import io.bitdive.parent.utils.MethodTypeEnum; 8 | import org.aspectj.lang.ProceedingJoinPoint; 9 | import org.aspectj.lang.annotation.Around; 10 | import org.aspectj.lang.annotation.Aspect; 11 | import org.aspectj.lang.reflect.MethodSignature; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.time.OffsetDateTime; 15 | 16 | import static io.bitdive.parent.message_producer.MessageService.sendMessageEnd; 17 | import static io.bitdive.parent.message_producer.MessageService.sendMessageStart; 18 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.*; 19 | 20 | @Component 21 | @Aspect 22 | public class RepositoryAspect { 23 | 24 | @Around(" (execution(* org.springframework.data.repository.Repository+.*(..)) || execution(* org.springframework.data.jpa.repository.JpaRepository+.*(..)) ) && !execution(* java.lang.Object.*(..))") 25 | public Object aroundRepositoryMethods(ProceedingJoinPoint joinPoint) throws Throwable { 26 | if (LoggerStatusContent.getEnabledProfile()) return joinPoint.proceed(); 27 | String UUIDMessage = UuidCreator.getTimeBased().toString(); 28 | Object retVal = null; 29 | Throwable thrown = null; 30 | MethodSignature methodSig = (MethodSignature) joinPoint.getSignature(); 31 | 32 | try { 33 | 34 | sendMessageStart( 35 | UUIDMessage, 36 | methodSig.getDeclaringTypeName(), 37 | methodSig.getName(), 38 | ContextManager.getTraceId(), 39 | ContextManager.getSpanId(), 40 | OffsetDateTime.now(), 41 | ContextManager.getParentIdMessageIdQueue(), 42 | false, 43 | ReflectionUtils.objectToString(paramConvert(joinPoint.getArgs(), methodSig.getMethod())), 44 | MethodTypeEnum.DB.toString(), "", "", 45 | ContextManager.getMethodInpointName(), 46 | ContextManager.getMessageInpointId(), 47 | ContextManager.getClassInpointName() 48 | ); 49 | 50 | ContextManager.setMethodCallContextQueue(UUIDMessage); 51 | 52 | retVal = joinPoint.proceed(); 53 | 54 | } catch (Throwable t) { 55 | thrown = t; 56 | throw t; 57 | } finally { 58 | 59 | sendMessageEnd( 60 | UUIDMessage, 61 | OffsetDateTime.now(), 62 | getaNullThrowable(thrown), 63 | ReflectionUtils.objectToString(methodReturnConvert(retVal)), 64 | ContextManager.getTraceId(), 65 | ContextManager.getSpanId() 66 | ); 67 | 68 | ContextManager.removeLastQueue(); 69 | } 70 | 71 | return retVal; 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/byte_buddy_agent/ByteBuddyAgentCatalinaResponse.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.byte_buddy_agent; 2 | 3 | import io.bitdive.parent.trasirovka.agent.utils.ContextManager; 4 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 5 | import net.bytebuddy.agent.builder.AgentBuilder; 6 | import net.bytebuddy.agent.builder.ResettableClassFileTransformer; 7 | import net.bytebuddy.asm.Advice; 8 | import net.bytebuddy.matcher.ElementMatchers; 9 | 10 | import java.lang.instrument.Instrumentation; 11 | import java.lang.reflect.Method; 12 | import java.util.Optional; 13 | 14 | import static io.bitdive.parent.message_producer.MessageService.sendMessageWebResponse; 15 | 16 | public class ByteBuddyAgentCatalinaResponse { 17 | public static ResettableClassFileTransformer init(Instrumentation instrumentation) { 18 | return new AgentBuilder.Default() 19 | .type(ElementMatchers.named("org.apache.catalina.connector.Request")) 20 | .transform((builder, typeDescription, classLoader, module, dd) -> 21 | builder.visit(Advice.to(CatalinaResponseInterceptor.class) 22 | .on(ElementMatchers.named("finishRequest"))) 23 | ) 24 | .installOn(instrumentation); 25 | } 26 | 27 | public static class CatalinaResponseInterceptor { 28 | 29 | @Advice.OnMethodEnter 30 | public static void onEnter(@Advice.This Object responseObj) { 31 | if (LoggerStatusContent.getEnabledProfile()) return; 32 | try { 33 | if (Optional.of(ContextManager.getUrlStart()).orElse("").toLowerCase().contains("/actuator/")) return; 34 | 35 | Class requestClass = responseObj.getClass(); 36 | 37 | Method getResponseMethod = requestClass.getMethod("getResponse"); 38 | Object responseInternal = getResponseMethod.invoke(responseObj); 39 | 40 | Class responseClass = responseInternal.getClass(); 41 | Method getStatusMethod = responseClass.getMethod("getStatus"); 42 | int status = (int) getStatusMethod.invoke(responseInternal); 43 | 44 | // finalize collected request body into context 45 | try { 46 | byte[] bodyBytes = io.bitdive.parent.trasirovka.agent.utils.RequestBodyCollector.getBytes(); 47 | if (bodyBytes != null) { 48 | ContextManager.setRequestBodyBytes(bodyBytes); 49 | } 50 | } catch (Exception ignored) { 51 | } 52 | 53 | sendMessageWebResponse( 54 | ContextManager.getMessageStart(), 55 | ContextManager.getTraceId(), 56 | ContextManager.getSpanId(), 57 | status 58 | ); 59 | } catch (Exception e) { 60 | if (LoggerStatusContent.isErrorsOrDebug()) 61 | System.err.println("error call finishRequest for org.apache.catalina.connector.Request error : " + e.getMessage()); 62 | 63 | } 64 | } 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BitDive Java Producer 2 | 3 | BitDive Java Producer is a Java agent and Spring integration library that collects runtime execution data for BitDive. It instruments Java applications at method level, captures HTTP and DB calls, builds distributed traces, and sends the collected data to the BitDive backend. 4 | 5 | ## What It Does 6 | 7 | - Instruments code with ByteBuddy at runtime 8 | - Captures method calls, parameters, results, exceptions 9 | - Captures HTTP client and server calls 10 | - Captures JDBC queries and timings 11 | - Propagates trace id and span id across services 12 | - Buffers data locally and uploads it in batches 13 | - Integrates with Spring Boot through auto configuration 14 | - Collects JVM metrics 15 | - Allows selective monitoring through annotations 16 | 17 | ## Repository Structure 18 | 19 | ``` 20 | java-producer-parent 21 | ├─ perf-monitoring-producer core agent and instrumentation 22 | ├─ perf-monitoring-producer-spring-2.7 Spring Boot 2.7 support 23 | ├─ perf-monitoring-producer-spring-3 Spring Boot 3 support 24 | └─ examples sample apps 25 | ``` 26 | 27 | ## Key Features 28 | 29 | ### Bytecode Instrumentation 30 | - Automatic method tracing 31 | - HTTP client and server hooks 32 | - JDBC hooks for queries and timings 33 | - Kafka producer and consumer hooks 34 | - Thread context propagation with trace id and span id 35 | 36 | ### Spring Boot Support 37 | - Auto configuration for Spring Boot 38 | - AOP aspects for repositories, Feign, Kafka, schedulers 39 | - Full integration with Spring context lifecycle 40 | 41 | ### Data Collection Pipeline 42 | 43 | 1. Instrumented code records events 44 | 2. Events are formatted into trace segments 45 | 3. Segments are written to local files 46 | 4. Upload service sends batches to BitDive backend 47 | 48 | ## Installation 49 | 50 | Add the dependency from Maven: 51 | 52 | ```xml 53 | 54 | io.bitdive 55 | perf-monitoring-producer 56 | YOUR_VERSION 57 | 58 | ``` 59 | 60 | For Spring Boot: 61 | 62 | ```xml 63 | 64 | io.bitdive 65 | perf-monitoring-producer-spring-3 66 | YOUR_VERSION 67 | 68 | ``` 69 | 70 | ## Configuration 71 | 72 | Create a file `bitdive-config.yml` in your resources: 73 | 74 | ```yaml 75 | service: 76 | name: my-service 77 | module: user-api 78 | 79 | monitoring: 80 | captureArguments: true 81 | captureResults: true 82 | 83 | upload: 84 | endpoint: https://bitdive.io/api/ingest 85 | batchSize: 2000 86 | ``` 87 | 88 | ## Annotations 89 | 90 | - `@MonitoringClass` enables monitoring for a class 91 | - `@NotMonitoring` disables monitoring for specific methods 92 | 93 | These are optional. The agent works automatically without them. 94 | 95 | ## Supported Technologies 96 | 97 | - Spring Boot 2.7 and 3 98 | - Servlet API 99 | - RestTemplate and Feign 100 | - JDBC 101 | - Kafka 102 | - Thread pools and executors 103 | 104 | ## Building 105 | 106 | ``` 107 | mvn clean package 108 | ``` 109 | 110 | ## Documentation 111 | 112 | See full BitDive docs: 113 | [https://bitdive.io/docs](https://bitdive.io/docs/getting-started/) 114 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/byte_buddy_agent/ByteBuddySimpleClientHttpResponse.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.byte_buddy_agent; 2 | 3 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 4 | import net.bytebuddy.agent.builder.AgentBuilder; 5 | import net.bytebuddy.agent.builder.ResettableClassFileTransformer; 6 | import net.bytebuddy.description.modifier.Visibility; 7 | import net.bytebuddy.implementation.MethodDelegation; 8 | import net.bytebuddy.implementation.bind.annotation.RuntimeType; 9 | import net.bytebuddy.implementation.bind.annotation.SuperCall; 10 | import net.bytebuddy.implementation.bind.annotation.This; 11 | import net.bytebuddy.matcher.ElementMatchers; 12 | 13 | import java.io.ByteArrayInputStream; 14 | import java.io.ByteArrayOutputStream; 15 | import java.io.IOException; 16 | import java.io.InputStream; 17 | import java.lang.instrument.Instrumentation; 18 | import java.lang.reflect.Field; 19 | import java.util.concurrent.Callable; 20 | 21 | public class ByteBuddySimpleClientHttpResponse { 22 | public static ResettableClassFileTransformer init(Instrumentation instrumentation) { 23 | try { 24 | Class clientClass = Class.forName("org.springframework.http.client.ClientHttpResponse"); 25 | return new AgentBuilder.Default() 26 | .type(ElementMatchers.nameContains("org.springframework").and(ElementMatchers.isSubTypeOf(clientClass))) 27 | .transform((builder, typeDescription, classLoader, module, dd) -> 28 | builder.defineField("cachedBody", byte[].class, Visibility.PRIVATE) 29 | .method(ElementMatchers.named("getBody")) 30 | .intercept(MethodDelegation.to(GetBodyInterceptor.class)) 31 | ).installOn(instrumentation); 32 | } catch (Exception e) { 33 | if (LoggerStatusContent.isErrorsOrDebug()) 34 | System.err.println("Not found class feign.Client in ClassLoader."); 35 | } 36 | return null; 37 | } 38 | 39 | 40 | public static class GetBodyInterceptor { 41 | 42 | @RuntimeType 43 | public static InputStream intercept(@SuperCall Callable zuper, @This Object obj) throws Exception { 44 | 45 | Field cachedBodyField = obj.getClass().getDeclaredField("cachedBody"); 46 | cachedBodyField.setAccessible(true); 47 | byte[] cachedBody = (byte[]) cachedBodyField.get(obj); 48 | 49 | if (cachedBody != null) { 50 | return new ByteArrayInputStream(cachedBody); 51 | } 52 | 53 | InputStream originalInputStream = zuper.call(); 54 | byte[] responseBodyBytes = readAllBytes(originalInputStream); 55 | cachedBodyField.set(obj, responseBodyBytes); 56 | return new ByteArrayInputStream(responseBodyBytes); 57 | } 58 | 59 | private static byte[] readAllBytes(InputStream inputStream) throws IOException { 60 | ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 61 | int nRead; 62 | byte[] data = new byte[16384]; // 16KB буфер 63 | while ((nRead = inputStream.read(data, 0, data.length)) != -1) { 64 | buffer.write(data, 0, nRead); 65 | } 66 | return buffer.toByteArray(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-2.7/src/main/java/io/bitdive/aspect/SchedulerAspect.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.aspect; 2 | 3 | import com.github.f4b6a3.uuid.UuidCreator; 4 | import io.bitdive.parent.trasirovka.agent.utils.ContextManager; 5 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 6 | import io.bitdive.parent.trasirovka.agent.utils.ReflectionUtils; 7 | import io.bitdive.parent.utils.MethodTypeEnum; 8 | import org.aspectj.lang.ProceedingJoinPoint; 9 | import org.aspectj.lang.annotation.Around; 10 | import org.aspectj.lang.annotation.Aspect; 11 | import org.aspectj.lang.reflect.MethodSignature; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.time.OffsetDateTime; 15 | 16 | import static io.bitdive.parent.message_producer.MessageService.sendMessageEnd; 17 | import static io.bitdive.parent.message_producer.MessageService.sendMessageStart; 18 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.*; 19 | 20 | @Component 21 | @Aspect 22 | public class SchedulerAspect { 23 | @Around("@annotation(org.springframework.scheduling.annotation.Scheduled)") 24 | public Object aroundFeignClientMethods(ProceedingJoinPoint joinPoint) throws Throwable { 25 | if (LoggerStatusContent.getEnabledProfile()) return joinPoint.proceed(); 26 | ContextManager.createNewRequest(); 27 | //if (!ContextManager.isMessageIdQueueEmpty()) return joinPoint.proceed(); 28 | 29 | String UUIDMessage = UuidCreator.getTimeBased().toString(); 30 | Object retVal = null; 31 | Throwable thrown = null; 32 | MethodSignature methodSig = (MethodSignature) joinPoint.getSignature(); 33 | 34 | try { 35 | ContextManager.setMethodInpointName(methodSig.getName()); 36 | ContextManager.setClassInpointName(methodSig.getDeclaringTypeName()); 37 | ContextManager.setMessageInpointId(UUIDMessage); 38 | 39 | sendMessageStart( 40 | UUIDMessage, 41 | methodSig.getDeclaringTypeName(), 42 | methodSig.getName(), 43 | ContextManager.getTraceId(), 44 | ContextManager.getSpanId(), 45 | OffsetDateTime.now(), 46 | ContextManager.getParentIdMessageIdQueue(), 47 | true, 48 | ReflectionUtils.objectToString(paramConvert(joinPoint.getArgs(), methodSig.getMethod())), 49 | MethodTypeEnum.SCHEDULER.toString(), "", "", 50 | ContextManager.getMethodInpointName(), 51 | ContextManager.getMessageInpointId(), 52 | ContextManager.getClassInpointName() 53 | ); 54 | 55 | ContextManager.setMethodCallContextQueue(UUIDMessage); 56 | 57 | retVal = joinPoint.proceed(); 58 | 59 | } catch (Throwable t) { 60 | thrown = t; 61 | throw t; 62 | } finally { 63 | 64 | sendMessageEnd( 65 | UUIDMessage, 66 | OffsetDateTime.now(), 67 | getaNullThrowable(thrown), 68 | ReflectionUtils.objectToString(methodReturnConvert(retVal)), 69 | ContextManager.getTraceId(), 70 | ContextManager.getSpanId() 71 | ); 72 | 73 | ContextManager.removeLastQueue(); 74 | } 75 | 76 | return retVal; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/src/main/java/io/bitdive/aspect/SchedulerAspect.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.aspect; 2 | 3 | import com.github.f4b6a3.uuid.UuidCreator; 4 | import io.bitdive.parent.trasirovka.agent.utils.ContextManager; 5 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 6 | import io.bitdive.parent.trasirovka.agent.utils.ReflectionUtils; 7 | import io.bitdive.parent.utils.MethodTypeEnum; 8 | import org.aspectj.lang.ProceedingJoinPoint; 9 | import org.aspectj.lang.annotation.Around; 10 | import org.aspectj.lang.annotation.Aspect; 11 | import org.aspectj.lang.reflect.MethodSignature; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.time.OffsetDateTime; 15 | 16 | import static io.bitdive.parent.message_producer.MessageService.sendMessageEnd; 17 | import static io.bitdive.parent.message_producer.MessageService.sendMessageStart; 18 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.*; 19 | 20 | @Component 21 | @Aspect 22 | public class SchedulerAspect { 23 | @Around("@annotation(org.springframework.scheduling.annotation.Scheduled)") 24 | public Object aroundFeignClientMethods(ProceedingJoinPoint joinPoint) throws Throwable { 25 | if (LoggerStatusContent.getEnabledProfile()) return joinPoint.proceed(); 26 | ContextManager.createNewRequest(); 27 | //if (!ContextManager.isMessageIdQueueEmpty()) return joinPoint.proceed(); 28 | 29 | String UUIDMessage = UuidCreator.getTimeBased().toString(); 30 | Object retVal = null; 31 | Throwable thrown = null; 32 | MethodSignature methodSig = (MethodSignature) joinPoint.getSignature(); 33 | 34 | try { 35 | 36 | ContextManager.setMethodInpointName(methodSig.getName()); 37 | ContextManager.setClassInpointName(methodSig.getDeclaringTypeName()); 38 | ContextManager.setMessageInpointId(UUIDMessage); 39 | 40 | sendMessageStart( 41 | UUIDMessage, 42 | methodSig.getDeclaringTypeName(), 43 | methodSig.getName(), 44 | ContextManager.getTraceId(), 45 | ContextManager.getSpanId(), 46 | OffsetDateTime.now(), 47 | ContextManager.getParentIdMessageIdQueue(), 48 | true, 49 | ReflectionUtils.objectToString(paramConvert(joinPoint.getArgs(), methodSig.getMethod())), 50 | MethodTypeEnum.SCHEDULER.toString(), "", "", 51 | ContextManager.getMethodInpointName(), 52 | ContextManager.getMessageInpointId(), 53 | ContextManager.getClassInpointName() 54 | ); 55 | 56 | ContextManager.setMethodCallContextQueue(UUIDMessage); 57 | 58 | retVal = joinPoint.proceed(); 59 | 60 | } catch (Throwable t) { 61 | thrown = t; 62 | throw t; 63 | } finally { 64 | 65 | sendMessageEnd( 66 | UUIDMessage, 67 | OffsetDateTime.now(), 68 | getaNullThrowable(thrown), 69 | ReflectionUtils.objectToString(methodReturnConvert(retVal)), 70 | ContextManager.getTraceId(), 71 | ContextManager.getSpanId() 72 | ); 73 | 74 | ContextManager.removeLastQueue(); 75 | } 76 | 77 | return retVal; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/safety_config/VaultGettingConfig.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.safety_config; 2 | 3 | import com.bettercloud.vault.SslConfig; 4 | import com.bettercloud.vault.Vault; 5 | import com.bettercloud.vault.VaultConfig; 6 | import com.bettercloud.vault.VaultException; 7 | import com.bettercloud.vault.response.LogicalResponse; 8 | import io.bitdive.parent.parserConfig.YamlParserConfig; 9 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 10 | 11 | import java.util.concurrent.Executors; 12 | import java.util.concurrent.ScheduledExecutorService; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | import static io.bitdive.parent.message_producer.LocalCryptoService.addKeyPrivateKey; 16 | import static io.bitdive.parent.message_producer.LocalCryptoService.addKeySecretKey; 17 | 18 | public class VaultGettingConfig { 19 | private static final String ENCRYPTION_KEY_PATH = "transit/export/encryption-key/encryption-key"; 20 | private static final String SIGNING_KEY_PATH = "transit/export/signing-key/signing-key"; 21 | 22 | 23 | private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); 24 | 25 | public static Vault initVault() { 26 | Vault vault = null; 27 | try { 28 | vault = new Vault(new VaultConfig() 29 | .address(YamlParserConfig.getProfilingConfig().getMonitoring().getSendFiles().getVault().getUrl()) 30 | .token(YamlParserConfig.getProfilingConfig().getMonitoring().getSendFiles().getVault().getToken()) 31 | .sslConfig(new SslConfig().verify(false).build()) 32 | .engineVersion(1) 33 | .build()); 34 | } catch (Exception e) { 35 | throw new RuntimeException(e); 36 | } 37 | return vault; 38 | } 39 | 40 | public static void initVaultConnect() { 41 | try { 42 | updateAESKey(); 43 | updateRSAPrivateKey(); 44 | startKeyUpdates(); 45 | } catch (Exception e) { 46 | throw new RuntimeException(e); 47 | } 48 | } 49 | 50 | public static void startKeyUpdates() { 51 | Runnable updateTask = new Runnable() { 52 | @Override 53 | public void run() { 54 | try { 55 | updateAESKey(); 56 | updateRSAPrivateKey(); 57 | if (LoggerStatusContent.isDebug()) 58 | System.out.println("keys were successfully updated in " + java.time.LocalDateTime.now()); 59 | } catch (Exception e) { 60 | if (LoggerStatusContent.isDebug()) 61 | System.out.println("error successfully updated :" + e.getMessage()); 62 | } 63 | } 64 | }; 65 | 66 | scheduler.scheduleAtFixedRate(updateTask, 0, 1, TimeUnit.HOURS); 67 | } 68 | 69 | public static void updateAESKey() throws VaultException { 70 | LogicalResponse response = initVault().logical().read(ENCRYPTION_KEY_PATH); 71 | Integer maxKeyId = response.getDataObject().get("keys").asObject().names().stream() 72 | .map(Integer::parseInt) 73 | .max(Integer::compareTo) 74 | .orElse(null); 75 | addKeySecretKey(maxKeyId, response.getDataObject().get("keys").asObject().get(String.valueOf(maxKeyId)).asString()); 76 | } 77 | 78 | public static void updateRSAPrivateKey() throws Exception { 79 | LogicalResponse response = initVault().logical().read(SIGNING_KEY_PATH); 80 | Integer maxKeyId = response.getDataObject().get("keys").asObject().names().stream() 81 | .map(Integer::parseInt) 82 | .max(Integer::compareTo) 83 | .orElse(null); 84 | addKeyPrivateKey(maxKeyId, response.getDataObject().get("keys").asObject().get(String.valueOf(maxKeyId)).asString()); 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-2.7/src/main/java/io/bitdive/aspect/RepositoryAspect.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.aspect; 2 | 3 | import com.github.f4b6a3.uuid.UuidCreator; 4 | import io.bitdive.parent.parserConfig.YamlParserConfig; 5 | import io.bitdive.parent.trasirovka.agent.utils.ContextManager; 6 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 7 | import io.bitdive.parent.trasirovka.agent.utils.ReflectionUtils; 8 | import io.bitdive.parent.utils.MethodTypeEnum; 9 | import org.aspectj.lang.ProceedingJoinPoint; 10 | import org.aspectj.lang.annotation.Around; 11 | import org.aspectj.lang.annotation.Aspect; 12 | import org.aspectj.lang.reflect.MethodSignature; 13 | import org.springframework.stereotype.Component; 14 | import org.springframework.stereotype.Repository; 15 | 16 | import java.time.OffsetDateTime; 17 | import java.util.Arrays; 18 | 19 | import static io.bitdive.parent.message_producer.MessageService.sendMessageEnd; 20 | import static io.bitdive.parent.message_producer.MessageService.sendMessageStart; 21 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.*; 22 | 23 | @Component 24 | @Aspect 25 | public class RepositoryAspect { 26 | 27 | @Around( 28 | "execution(* *(..))" 29 | + " && target(org.springframework.data.repository.Repository+)" 30 | + " && !execution(* java.lang.Object.*(..))" 31 | ) 32 | public Object aroundRepositoryMethods(ProceedingJoinPoint joinPoint) throws Throwable { 33 | if (LoggerStatusContent.getEnabledProfile()) return joinPoint.proceed(); 34 | String UUIDMessage = UuidCreator.getTimeBased().toString(); 35 | Object retVal = null; 36 | Throwable thrown = null; 37 | MethodSignature methodSig = (MethodSignature) joinPoint.getSignature(); 38 | 39 | 40 | Class[] ifcs = joinPoint.getTarget().getClass().getInterfaces(); 41 | 42 | 43 | Class repoIface = Arrays.stream(ifcs) 44 | .filter(i -> 45 | i.isAnnotationPresent(Repository.class) || 46 | Arrays.stream(YamlParserConfig.getProfilingConfig().getApplication().getPackedScanner()) 47 | .anyMatch(s -> i.getName().contains(s)) 48 | 49 | ) 50 | .findFirst() 51 | 52 | .orElse(methodSig.getDeclaringType()); 53 | 54 | String repoName = repoIface.getName(); 55 | String methodName = methodSig.getName(); 56 | 57 | 58 | try { 59 | 60 | sendMessageStart( 61 | UUIDMessage, 62 | repoName, 63 | methodName, 64 | ContextManager.getTraceId(), 65 | ContextManager.getSpanId(), 66 | OffsetDateTime.now(), 67 | ContextManager.getParentIdMessageIdQueue(), 68 | false, 69 | ReflectionUtils.objectToString(paramConvert(joinPoint.getArgs(), methodSig.getMethod())), 70 | MethodTypeEnum.DB.toString(), "", "", 71 | ContextManager.getMethodInpointName(), 72 | ContextManager.getMessageInpointId(), 73 | ContextManager.getClassInpointName() 74 | ); 75 | 76 | ContextManager.setMethodCallContextQueue(UUIDMessage); 77 | 78 | retVal = joinPoint.proceed(); 79 | 80 | } catch (Throwable t) { 81 | thrown = t; 82 | throw t; 83 | } finally { 84 | 85 | sendMessageEnd( 86 | UUIDMessage, 87 | OffsetDateTime.now(), 88 | getaNullThrowable(thrown), 89 | ReflectionUtils.objectToString(methodReturnConvert(retVal)), 90 | ContextManager.getTraceId(), 91 | ContextManager.getSpanId() 92 | ); 93 | 94 | ContextManager.removeLastQueue(); 95 | } 96 | 97 | return retVal; 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/safety_config/SSLContextCustomBitDive.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.safety_config; 2 | 3 | import io.bitdive.parent.parserConfig.YamlParserConfig; 4 | 5 | 6 | import javax.net.ssl.*; 7 | import java.net.URL; 8 | import java.security.KeyStore; 9 | import java.security.SecureRandom; 10 | import java.security.cert.Certificate; 11 | import java.security.cert.X509Certificate; 12 | 13 | public class SSLContextCustomBitDive { 14 | 15 | // ---------- контексты ---------- 16 | private static volatile SSLContext strictCtx; 17 | private static volatile SSLContext trustAllCtx; 18 | 19 | /** 20 | * Строгий контекст с цепочкой сервера 21 | */ 22 | public static SSLContext strict() { 23 | if (strictCtx == null) { 24 | synchronized (SSLContextCustomBitDive.class) { 25 | if (strictCtx == null) { 26 | strictCtx = createStrictContext(); 27 | } 28 | } 29 | } 30 | return strictCtx; 31 | } 32 | 33 | /** 34 | * Контекст, отключающий все проверки – использовать ТОЛЬКО как fallback 35 | */ 36 | public static SSLContext trustAll() { 37 | if (trustAllCtx == null) { 38 | synchronized (SSLContextCustomBitDive.class) { 39 | if (trustAllCtx == null) { 40 | trustAllCtx = createTrustAllContext(); 41 | } 42 | } 43 | } 44 | return trustAllCtx; 45 | } 46 | 47 | // ---- internal ---- 48 | private static SSLContext createStrictContext() { 49 | try { 50 | URL url = new URL(YamlParserConfig.getProfilingConfig() 51 | .getMonitoring() 52 | .getSendFiles() 53 | .getServerConsumer() 54 | .getUrl()); 55 | Certificate[] chain = fetchServerChain(url.getHost(), 443); 56 | return buildSslContextWithChain(chain); 57 | } catch (Exception e) { 58 | throw new IllegalStateException("Can't build strict SSLContext", e); 59 | } 60 | } 61 | 62 | private static SSLContext buildSslContextWithChain(Certificate[] chain) throws Exception { 63 | KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); 64 | ks.load(null, null); 65 | 66 | // добавляем все сертификаты из цепочки 67 | for (int i = 0; i < chain.length; i++) { 68 | ks.setCertificateEntry("cert-" + i, chain[i]); 69 | } 70 | 71 | TrustManagerFactory tmf = 72 | TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 73 | tmf.init(ks); 74 | 75 | SSLContext ctx = SSLContext.getInstance("TLS"); 76 | ctx.init(null, tmf.getTrustManagers(), new SecureRandom()); 77 | return ctx; 78 | } 79 | 80 | private static Certificate[] fetchServerChain(String host, int port) throws Exception { 81 | SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault(); 82 | try (SSLSocket socket = (SSLSocket) factory.createSocket(host, port)) { 83 | socket.startHandshake(); 84 | return socket.getSession().getPeerCertificates(); // leaf + intermediates 85 | } 86 | } 87 | 88 | private static SSLContext createTrustAllContext() { 89 | try { 90 | TrustManager[] trustAll = {new X509TrustManager() { 91 | public void checkClientTrusted(X509Certificate[] c, String a) { 92 | } 93 | 94 | public void checkServerTrusted(X509Certificate[] c, String a) { 95 | } 96 | 97 | public X509Certificate[] getAcceptedIssuers() { 98 | return new X509Certificate[0]; 99 | } 100 | }}; 101 | SSLContext ctx = SSLContext.getInstance("TLS"); 102 | ctx.init(null, trustAll, new SecureRandom()); 103 | return ctx; 104 | } catch (Exception e) { 105 | throw new IllegalStateException("Can't build trust-all SSLContext", e); 106 | } 107 | } 108 | } 109 | 110 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/parserConfig/HttpsURLConnectionCustom.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.parserConfig; 2 | 3 | import com.fasterxml.jackson.core.type.TypeReference; 4 | import com.fasterxml.jackson.databind.DeserializationFeature; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import io.bitdive.parent.safety_config.SSLContextCustomBitDive; 7 | 8 | import javax.net.ssl.HostnameVerifier; 9 | import javax.net.ssl.HttpsURLConnection; 10 | import javax.net.ssl.SSLContext; 11 | import java.io.*; 12 | import java.net.HttpURLConnection; 13 | import java.net.URL; 14 | import java.nio.charset.StandardCharsets; 15 | import java.security.AccessControlException; 16 | import java.time.Duration; 17 | import java.util.stream.Collectors; 18 | 19 | public class HttpsURLConnectionCustom { 20 | 21 | private static final ObjectMapper MAPPER = new ObjectMapper() 22 | .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 23 | 24 | 25 | public static ProfilingConfig requestConfigForService(ConfigForServiceDTO dto) { 26 | String endpoint = dto.getServerUrl().replaceAll("/+$", "") + "/monitoring-api/service/serviceConfiguration/getConfigForService"; 27 | try { 28 | URL url = new URL(endpoint); 29 | try { 30 | HttpURLConnection conn = 31 | endpoint.contains("https://") ? 32 | (HttpsURLConnection) url.openConnection() : 33 | (HttpURLConnection) url.openConnection(); 34 | 35 | return doRequest(conn, dto); 36 | } catch (Exception e) { 37 | throw new RuntimeException(e); 38 | } 39 | } catch (AccessControlException e) { 40 | System.out.println("Error of read config from server bitDive " + endpoint + " Access Control Exception"); 41 | throw new RuntimeException(e); 42 | } catch (Exception e) { 43 | throw new RuntimeException("Error of read config from server bitDive " + endpoint, e); 44 | } 45 | } 46 | 47 | private static ProfilingConfig doRequest(HttpURLConnection httpURLConnection, ConfigForServiceDTO dto) throws Exception { 48 | 49 | 50 | byte[] body = MAPPER.writeValueAsBytes(dto); 51 | 52 | if (httpURLConnection instanceof HttpsURLConnection) { 53 | HttpsURLConnection conn = (HttpsURLConnection) httpURLConnection; 54 | SSLContext ctx = SSLContextCustomBitDive.trustAll(); 55 | HostnameVerifier hv = (h, s) -> true; 56 | 57 | conn.setSSLSocketFactory(ctx.getSocketFactory()); 58 | conn.setHostnameVerifier(hv); 59 | return getProfilingConfig(body, conn); 60 | } else { 61 | return getProfilingConfig(body, httpURLConnection); 62 | } 63 | 64 | 65 | } 66 | 67 | private static ProfilingConfig getProfilingConfig(byte[] body, HttpURLConnection conn) throws IOException { 68 | int code; 69 | int timeout = (int) Duration.ofSeconds(10).toMillis(); 70 | conn.setConnectTimeout(timeout); 71 | conn.setReadTimeout(timeout); 72 | conn.setRequestMethod("POST"); 73 | conn.setDoOutput(true); 74 | conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); 75 | conn.setRequestProperty("Accept", "application/json"); 76 | 77 | try (OutputStream os = conn.getOutputStream()) { 78 | os.write(body); 79 | } 80 | code = conn.getResponseCode(); 81 | try (InputStream is = code < 400 ? conn.getInputStream() : conn.getErrorStream()) { 82 | if (code >= 200 && code < 300) { 83 | return MAPPER.readValue(is, new TypeReference() { 84 | }); 85 | } else if (code == 401) { 86 | throw new AccessControlException("Unauthorized failed"); 87 | } else { 88 | String error; 89 | try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { 90 | error = br.lines().collect(Collectors.joining("\n")); 91 | } 92 | throw new IllegalStateException("BitDive server returned " + code + ": " + error); 93 | } 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/message_producer/HttpsURLConnectionCustom.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.message_producer; 2 | 3 | import io.bitdive.parent.safety_config.SSLContextCustomBitDive; 4 | import io.bitdive.parent.utils.Pair; 5 | 6 | import javax.net.ssl.HostnameVerifier; 7 | import javax.net.ssl.HttpsURLConnection; 8 | import javax.net.ssl.SSLContext; 9 | import java.io.*; 10 | import java.net.URL; 11 | import java.nio.charset.StandardCharsets; 12 | import java.nio.file.Files; 13 | 14 | public class HttpsURLConnectionCustom { 15 | 16 | private static final String BOUNDARY = "*****" + System.currentTimeMillis() + "*****"; 17 | 18 | private static volatile boolean TRUST_ALL_MODE = false; 19 | 20 | public static int sentToServer(HttpsURLConnection connection, 21 | File file, 22 | Pair encryptedData, 23 | Pair signature) throws IOException { 24 | 25 | try { 26 | return send(connection, file, encryptedData, signature, !TRUST_ALL_MODE); 27 | } catch (Exception sslEx) { 28 | TRUST_ALL_MODE = true; 29 | URL url = connection.getURL(); 30 | HttpsURLConnection retryConn = (HttpsURLConnection) url.openConnection(); 31 | return send(retryConn, file, encryptedData, signature, false); 32 | } 33 | } 34 | 35 | private static int send(HttpsURLConnection connection, File file, Pair encryptedData, Pair signature, boolean strictTls) throws IOException { 36 | 37 | SSLContext ctx = strictTls ? SSLContextCustomBitDive.strict() 38 | : SSLContextCustomBitDive.trustAll(); 39 | HostnameVerifier hv = strictTls ? HttpsURLConnection.getDefaultHostnameVerifier() 40 | : (h, s) -> true; 41 | 42 | connection.setSSLSocketFactory(ctx.getSocketFactory()); 43 | connection.setHostnameVerifier(hv); 44 | 45 | connection.setRequestMethod("POST"); 46 | connection.setDoOutput(true); 47 | connection.setDoInput(true); 48 | connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY); 49 | connection.setRequestProperty("User-Agent", "Java client"); 50 | connection.setRequestProperty("Accept", "*/*"); 51 | 52 | 53 | try (OutputStream outputStream = connection.getOutputStream(); 54 | PrintWriter writer = new PrintWriter( 55 | new OutputStreamWriter(outputStream, StandardCharsets.UTF_8), true)) { 56 | 57 | final String LF = "\r\n"; 58 | 59 | 60 | writer.append("--").append(BOUNDARY).append(LF); 61 | writer.append("Content-Disposition: form-data; name=\"encryptedData\"; filename=\"") 62 | .append(file.getName()).append("\"").append(LF); 63 | writer.append("Content-Type: ").append(Files.probeContentType(file.toPath())).append(LF); 64 | writer.append(LF).flush(); 65 | outputStream.write(encryptedData.getVal()); 66 | outputStream.flush(); 67 | writer.append(LF).flush(); 68 | 69 | writer.append("--").append(BOUNDARY).append(LF); 70 | writer.append("Content-Disposition: form-data; name=\"encrypteKeyId\"").append(LF); 71 | writer.append("Content-Type: text/plain").append(LF).append(LF).flush(); 72 | writer.append(encryptedData.getKey().toString()).append(LF).flush(); 73 | 74 | 75 | writer.append("--").append(BOUNDARY).append(LF); 76 | writer.append("Content-Disposition: form-data; name=\"signature\"; filename=\"signature.bin\"").append(LF); 77 | writer.append("Content-Type: application/octet-stream").append(LF).append(LF).flush(); 78 | outputStream.write(signature.getVal()); 79 | outputStream.write(LF.getBytes(StandardCharsets.UTF_8)); 80 | outputStream.flush(); 81 | 82 | 83 | 84 | writer.append("--").append(BOUNDARY).append(LF); 85 | writer.append("Content-Disposition: form-data; name=\"signatureKeyId\"").append(LF); 86 | writer.append("Content-Type: text/plain").append(LF).append(LF).flush(); 87 | writer.append(signature.getKey().toString()).append(LF).flush(); 88 | 89 | 90 | writer.append("--").append(BOUNDARY).append("--").append(LF).flush(); 91 | } 92 | 93 | return connection.getResponseCode(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/byte_buddy_agent/ByteBuddyAgentSpringRawWs.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.byte_buddy_agent; 2 | 3 | import com.github.f4b6a3.uuid.UuidCreator; 4 | import io.bitdive.parent.message_producer.MessageService; 5 | import io.bitdive.parent.trasirovka.agent.utils.ContextManager; 6 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 7 | import io.bitdive.parent.trasirovka.agent.utils.ReflectionUtils; 8 | import net.bytebuddy.agent.builder.AgentBuilder; 9 | import net.bytebuddy.agent.builder.ResettableClassFileTransformer; 10 | import net.bytebuddy.implementation.MethodDelegation; 11 | import net.bytebuddy.implementation.bind.annotation.AllArguments; 12 | import net.bytebuddy.implementation.bind.annotation.Origin; 13 | import net.bytebuddy.implementation.bind.annotation.RuntimeType; 14 | import net.bytebuddy.implementation.bind.annotation.SuperCall; 15 | 16 | import java.lang.instrument.Instrumentation; 17 | import java.lang.reflect.Method; 18 | import java.time.OffsetDateTime; 19 | import java.util.concurrent.Callable; 20 | 21 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.getaNullThrowable; 22 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.paramConvert; 23 | import static net.bytebuddy.matcher.ElementMatchers.*; 24 | 25 | public class ByteBuddyAgentSpringRawWs { 26 | 27 | public static ResettableClassFileTransformer init(Instrumentation inst) { 28 | return new AgentBuilder.Default() 29 | .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) 30 | .type(hasSuperType(named("org.springframework.web.socket.handler.AbstractWebSocketHandler"))) 31 | .transform((builder, td, cl, module, pd) -> builder 32 | .method(named("handleTextMessage") 33 | .and(takesArguments(2)) 34 | .and(takesArgument(0, named("org.springframework.web.socket.WebSocketSession"))) 35 | .and(takesArgument(1, named("org.springframework.web.socket.TextMessage")))) 36 | .intercept(MethodDelegation.to(TextInterceptor.class)) 37 | ) 38 | .installOn(inst); 39 | } 40 | 41 | public static class TextInterceptor { 42 | @RuntimeType 43 | public static Object intercept(@SuperCall Callable zuper, 44 | @AllArguments Object[] args, 45 | @Origin Method method) throws Exception { 46 | if (LoggerStatusContent.getEnabledProfile()) { 47 | return zuper.call(); 48 | } 49 | 50 | ContextManager.createNewRequest(); 51 | String uuidMessage = UuidCreator.getTimeBased().toString(); 52 | OffsetDateTime startTime = OffsetDateTime.now(); 53 | Throwable thrown = null; 54 | 55 | ContextManager.setMethodCallContextQueue(uuidMessage); 56 | 57 | Object retVal; 58 | try { 59 | retVal = zuper.call(); 60 | } catch (Throwable t) { 61 | thrown = t; 62 | throw t; 63 | } finally { 64 | String destination = ""; 65 | try { 66 | Object session = args[0]; 67 | Object uri = session.getClass().getMethod("getUri").invoke(session); 68 | destination = uri != null ? uri.toString() : ""; 69 | } catch (Throwable ignore) { 70 | } 71 | 72 | String argsString = ReflectionUtils.objectToString(paramConvert(args, method)); 73 | ContextManager.setMessageInpointId(uuidMessage); 74 | ContextManager.setMethodCallContextQueue(method.getName()); 75 | MessageService.sendMessageRawWsConsumer( 76 | uuidMessage, 77 | method.getDeclaringClass().getName(), 78 | method.getName(), 79 | ContextManager.getTraceId(), 80 | ContextManager.getSpanId(), 81 | startTime, 82 | OffsetDateTime.now(), 83 | destination, 84 | argsString, 85 | getaNullThrowable(thrown), 86 | true, 87 | ContextManager.getMethodInpointName(), 88 | ContextManager.getMessageInpointId(), 89 | ContextManager.getClassInpointName() 90 | ); 91 | } 92 | return retVal; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /dependency-reduced-pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | io.bitdive 5 | java-producer-parent 6 | parent-producer 7 | 1.3.4 8 | library is a common module for the system for collecting profiling information 9 | bitdive.io 10 | 11 | 12 | FrolikovEA 13 | ef@bitdive.io 14 | 15 | 16 | 17 | 18 | BitDive.io Agent Proprietary License 19 | https://bitdive.io/docs/license 20 | repo 21 | 22 | 23 | 24 | scm:git:git://github.com/username/my-project.git 25 | scm:git:ssh://github.com/username/my-project.git 26 | https://github.com/username/my-project 27 | 28 | 29 | 30 | 31 | maven-gpg-plugin 32 | 1.6 33 | 34 | 35 | sign-artifacts 36 | verify 37 | 38 | sign 39 | 40 | 41 | 42 | 43 | C:\Program Files (x86)\GnuPG\bin\gpg.exe 44 | 45 | 46 | 47 | org.sonatype.central 48 | central-publishing-maven-plugin 49 | 0.6.0 50 | true 51 | 52 | central 53 | 54 | 55 | 56 | maven-source-plugin 57 | 3.2.1 58 | 59 | 60 | attach-sources 61 | 62 | jar 63 | 64 | 65 | 66 | 67 | 68 | maven-javadoc-plugin 69 | 3.2.0 70 | 71 | 72 | attach-javadocs 73 | 74 | jar 75 | 76 | 77 | 78 | 79 | 80 | maven-shade-plugin 81 | 3.2.4 82 | 83 | 84 | package 85 | 86 | shade 87 | 88 | 89 | 90 | 91 | *:* 92 | 93 | META-INF/*.SF 94 | META-INF/*.DSA 95 | META-INF/*.RSA 96 | META-INF/*.kotlin_module 97 | 98 | 99 | 100 | com.fasterxml.jackson.datatype:jackson-datatype-hibernate5 101 | com.fasterxml.jackson.datatype:jackson-datatype-hibernate6 102 | com.fasterxml.jackson.datatype:jackson-datatype-jsr310 103 | com.fasterxml.jackson.datatype:jackson-datatype-jdk8 104 | com.fasterxml.jackson.datatype:jackson-module-afterburner 105 | 106 | META-INF/services/com.fasterxml.jackson.databind.Module 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 1.8 118 | UTF-8 119 | 1.8 120 | 121 | 122 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-2.7/src/main/java/io/bitdive/aspect/StompSendToAspect.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.aspect; 2 | 3 | import com.github.f4b6a3.uuid.UuidCreator; 4 | import io.bitdive.parent.trasirovka.agent.utils.ContextManager; 5 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 6 | import io.bitdive.parent.trasirovka.agent.utils.ReflectionUtils; 7 | import org.aspectj.lang.ProceedingJoinPoint; 8 | import org.aspectj.lang.annotation.Around; 9 | import org.aspectj.lang.annotation.Aspect; 10 | import org.aspectj.lang.reflect.MethodSignature; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.core.env.Environment; 13 | import org.springframework.stereotype.Component; 14 | 15 | import java.lang.annotation.Annotation; 16 | import java.lang.reflect.Method; 17 | import java.time.OffsetDateTime; 18 | import java.util.concurrent.ConcurrentHashMap; 19 | import java.util.concurrent.ConcurrentMap; 20 | 21 | import static io.bitdive.parent.message_producer.MessageService.sendMessageStompSend; 22 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.getaNullThrowable; 23 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.methodReturnConvert; 24 | 25 | @Aspect 26 | @Component 27 | public class StompSendToAspect { 28 | 29 | @Autowired 30 | private Environment environment; 31 | 32 | private final ConcurrentMap sendToCache = new ConcurrentHashMap<>(); 33 | 34 | @Around("@annotation(org.springframework.messaging.handler.annotation.SendTo)") 35 | public Object aroundSendTo(ProceedingJoinPoint joinPoint) throws Throwable { 36 | if (LoggerStatusContent.getEnabledProfile()) return joinPoint.proceed(); 37 | String uuidMessage = UuidCreator.getTimeBased().toString(); 38 | Throwable thrown = null; 39 | MethodSignature methodSig = (MethodSignature) joinPoint.getSignature(); 40 | OffsetDateTime startTime = OffsetDateTime.now(); 41 | 42 | Method method = methodSig.getMethod(); 43 | String destination = sendToCache.get(method); 44 | if (destination == null) { 45 | destination = resolveSendToDestination(method); 46 | sendToCache.put(method, destination); 47 | } 48 | 49 | Object retVal = null; 50 | try { 51 | retVal = joinPoint.proceed(); 52 | return retVal; 53 | } catch (Throwable t) { 54 | thrown = t; 55 | throw t; 56 | } finally { 57 | sendMessageStompSend( 58 | uuidMessage, 59 | ContextManager.getSpanId(), 60 | ContextManager.getTraceId(), 61 | methodSig.getDeclaringTypeName(), 62 | methodSig.getName(), 63 | destination, 64 | ReflectionUtils.objectToString(methodReturnConvert(retVal)), 65 | startTime, 66 | OffsetDateTime.now(), 67 | ContextManager.getMessageIdQueueNew(), 68 | getaNullThrowable(thrown), 69 | ContextManager.getMethodInpointName(), 70 | ContextManager.getMessageInpointId(), 71 | ContextManager.getClassInpointName() 72 | ); 73 | } 74 | } 75 | 76 | private String resolveSendToDestination(Method method) { 77 | try { 78 | Annotation[] annotations = method.getDeclaredAnnotations(); 79 | for (Annotation annotation : annotations) { 80 | String name = annotation.annotationType().getName(); 81 | if ("org.springframework.messaging.handler.annotation.SendTo".equals(name)) { 82 | try { 83 | Method value = annotation.annotationType().getMethod("value"); 84 | String[] vals = (String[]) value.invoke(annotation); 85 | if (vals != null && vals.length > 0) { 86 | return environment.resolvePlaceholders(vals[0]); 87 | } 88 | } catch (NoSuchMethodException ignore) { 89 | } 90 | try { 91 | Method destinations = annotation.annotationType().getMethod("destinations"); 92 | String[] vals = (String[]) destinations.invoke(annotation); 93 | if (vals != null && vals.length > 0) { 94 | return environment.resolvePlaceholders(vals[0]); 95 | } 96 | } catch (NoSuchMethodException ignore) { 97 | } 98 | } 99 | } 100 | } catch (Exception e) { 101 | if (LoggerStatusContent.isErrorsOrDebug()) { 102 | System.err.println("resolveSendToDestination ERROR: " + e.getMessage()); 103 | } 104 | } 105 | return ""; 106 | } 107 | 108 | } 109 | 110 | 111 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/src/main/java/io/bitdive/aspect/StompSendToAspect.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.aspect; 2 | 3 | import com.github.f4b6a3.uuid.UuidCreator; 4 | import io.bitdive.parent.trasirovka.agent.utils.ContextManager; 5 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 6 | import io.bitdive.parent.trasirovka.agent.utils.ReflectionUtils; 7 | import org.aspectj.lang.ProceedingJoinPoint; 8 | import org.aspectj.lang.annotation.Around; 9 | import org.aspectj.lang.annotation.Aspect; 10 | import org.aspectj.lang.reflect.MethodSignature; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.core.env.Environment; 13 | import org.springframework.stereotype.Component; 14 | 15 | import java.lang.annotation.Annotation; 16 | import java.lang.reflect.Method; 17 | import java.time.OffsetDateTime; 18 | import java.util.concurrent.ConcurrentHashMap; 19 | import java.util.concurrent.ConcurrentMap; 20 | 21 | import static io.bitdive.parent.message_producer.MessageService.sendMessageStompSend; 22 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.getaNullThrowable; 23 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.methodReturnConvert; 24 | 25 | @Aspect 26 | @Component 27 | public class StompSendToAspect { 28 | 29 | @Autowired 30 | private Environment environment; 31 | 32 | private final ConcurrentMap sendToCache = new ConcurrentHashMap<>(); 33 | 34 | @Around("@annotation(org.springframework.messaging.handler.annotation.SendTo)") 35 | public Object aroundSendTo(ProceedingJoinPoint joinPoint) throws Throwable { 36 | if (LoggerStatusContent.getEnabledProfile()) return joinPoint.proceed(); 37 | String uuidMessage = UuidCreator.getTimeBased().toString(); 38 | Throwable thrown = null; 39 | MethodSignature methodSig = (MethodSignature) joinPoint.getSignature(); 40 | OffsetDateTime startTime = OffsetDateTime.now(); 41 | 42 | Method method = methodSig.getMethod(); 43 | String destination = sendToCache.get(method); 44 | if (destination == null) { 45 | destination = resolveSendToDestination(method); 46 | sendToCache.put(method, destination); 47 | } 48 | 49 | Object retVal = null; 50 | try { 51 | retVal = joinPoint.proceed(); 52 | return retVal; 53 | } catch (Throwable t) { 54 | thrown = t; 55 | throw t; 56 | } finally { 57 | sendMessageStompSend( 58 | uuidMessage, 59 | ContextManager.getSpanId(), 60 | ContextManager.getTraceId(), 61 | methodSig.getDeclaringTypeName(), 62 | methodSig.getName(), 63 | destination, 64 | ReflectionUtils.objectToString(methodReturnConvert(retVal)), 65 | startTime, 66 | OffsetDateTime.now(), 67 | ContextManager.getMessageIdQueueNew(), 68 | getaNullThrowable(thrown), 69 | ContextManager.getMethodInpointName(), 70 | ContextManager.getMessageInpointId(), 71 | ContextManager.getClassInpointName() 72 | ); 73 | } 74 | } 75 | 76 | private String resolveSendToDestination(Method method) { 77 | try { 78 | Annotation[] annotations = method.getDeclaredAnnotations(); 79 | for (Annotation annotation : annotations) { 80 | String name = annotation.annotationType().getName(); 81 | if ("org.springframework.messaging.handler.annotation.SendTo".equals(name)) { 82 | try { 83 | Method value = annotation.annotationType().getMethod("value"); 84 | String[] vals = (String[]) value.invoke(annotation); 85 | if (vals != null && vals.length > 0) { 86 | return environment.resolvePlaceholders(vals[0]); 87 | } 88 | } catch (NoSuchMethodException ignore) { 89 | } 90 | try { 91 | Method destinations = annotation.annotationType().getMethod("destinations"); 92 | String[] vals = (String[]) destinations.invoke(annotation); 93 | if (vals != null && vals.length > 0) { 94 | return environment.resolvePlaceholders(vals[0]); 95 | } 96 | } catch (NoSuchMethodException ignore) { 97 | } 98 | } 99 | } 100 | } catch (Exception e) { 101 | if (LoggerStatusContent.isErrorsOrDebug()) { 102 | System.err.println("resolveSendToDestination ERROR: " + e.getMessage()); 103 | } 104 | } 105 | return ""; 106 | } 107 | 108 | } 109 | 110 | 111 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/src/main/java/io/bitdive/aspect/StompMessageMappingAspect.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.aspect; 2 | 3 | import com.github.f4b6a3.uuid.UuidCreator; 4 | import io.bitdive.parent.trasirovka.agent.utils.ContextManager; 5 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 6 | import io.bitdive.parent.trasirovka.agent.utils.ReflectionUtils; 7 | import org.aspectj.lang.ProceedingJoinPoint; 8 | import org.aspectj.lang.annotation.Around; 9 | import org.aspectj.lang.annotation.Aspect; 10 | import org.aspectj.lang.reflect.MethodSignature; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.core.env.Environment; 13 | import org.springframework.stereotype.Component; 14 | 15 | import java.lang.annotation.Annotation; 16 | import java.lang.reflect.Method; 17 | import java.time.OffsetDateTime; 18 | import java.util.concurrent.ConcurrentHashMap; 19 | import java.util.concurrent.ConcurrentMap; 20 | 21 | import static io.bitdive.parent.message_producer.MessageService.sendMessageStompConsumer; 22 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.getaNullThrowable; 23 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.paramConvert; 24 | 25 | @Aspect 26 | @Component 27 | public class StompMessageMappingAspect { 28 | 29 | @Autowired 30 | private Environment environment; 31 | 32 | private final ConcurrentMap mappingCache = new ConcurrentHashMap<>(); 33 | 34 | @Around("@annotation(org.springframework.messaging.handler.annotation.MessageMapping)") 35 | public Object aroundMessageMapping(ProceedingJoinPoint joinPoint) throws Throwable { 36 | if (LoggerStatusContent.getEnabledProfile()) return joinPoint.proceed(); 37 | ContextManager.createNewRequest(); 38 | String uuidMessage = UuidCreator.getTimeBased().toString(); 39 | Throwable thrown = null; 40 | MethodSignature methodSig = (MethodSignature) joinPoint.getSignature(); 41 | OffsetDateTime startTime = OffsetDateTime.now(); 42 | 43 | Method method = methodSig.getMethod(); 44 | CachedMappingInfo cachedInfo = mappingCache.get(method); 45 | if (cachedInfo == null) { 46 | cachedInfo = resolveMessageMapping(method); 47 | mappingCache.put(method, cachedInfo); 48 | } 49 | 50 | ContextManager.setMethodCallContextQueue(uuidMessage); 51 | ContextManager.setMethodInpointName(methodSig.getName()); 52 | ContextManager.setClassInpointName(methodSig.getDeclaringTypeName()); 53 | ContextManager.setMessageInpointId(uuidMessage); 54 | Object retVal; 55 | try { 56 | retVal = joinPoint.proceed(); 57 | } catch (Throwable t) { 58 | thrown = t; 59 | throw t; 60 | } finally { 61 | String destination = cachedInfo.getDestination(); 62 | sendMessageStompConsumer( 63 | uuidMessage, 64 | methodSig.getDeclaringTypeName(), 65 | methodSig.getName(), 66 | ContextManager.getTraceId(), 67 | ContextManager.getSpanId(), 68 | startTime, 69 | OffsetDateTime.now(), 70 | destination, 71 | ReflectionUtils.objectToString(paramConvert(joinPoint.getArgs(), methodSig.getMethod())), 72 | getaNullThrowable(thrown), 73 | true, 74 | ContextManager.getMethodInpointName(), 75 | ContextManager.getMessageInpointId(), 76 | ContextManager.getClassInpointName() 77 | ); 78 | } 79 | return retVal; 80 | } 81 | 82 | private CachedMappingInfo resolveMessageMapping(Method method) { 83 | Annotation[] annotations = method.getDeclaredAnnotations(); 84 | for (Annotation annotation : annotations) { 85 | if (annotation.annotationType().getName().equals("org.springframework.messaging.handler.annotation.MessageMapping")) { 86 | try { 87 | Method valueMethod = annotation.annotationType().getMethod("value"); 88 | String[] values = (String[]) valueMethod.invoke(annotation); 89 | for (int i = 0; i < values.length; i++) values[i] = environment.resolvePlaceholders(values[i]); 90 | String destination = String.join(",", values); 91 | return new CachedMappingInfo(destination); 92 | } catch (Exception ignore) { 93 | return new CachedMappingInfo(""); 94 | } 95 | } 96 | } 97 | return new CachedMappingInfo(""); 98 | } 99 | 100 | private static class CachedMappingInfo { 101 | private final String destination; 102 | 103 | private CachedMappingInfo(String destination) { 104 | this.destination = destination; 105 | } 106 | 107 | public String getDestination() { 108 | return destination; 109 | } 110 | } 111 | } 112 | 113 | 114 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-2.7/src/main/java/io/bitdive/aspect/StompMessageMappingAspect.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.aspect; 2 | 3 | import com.github.f4b6a3.uuid.UuidCreator; 4 | import io.bitdive.parent.trasirovka.agent.utils.ContextManager; 5 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 6 | import io.bitdive.parent.trasirovka.agent.utils.ReflectionUtils; 7 | import org.aspectj.lang.ProceedingJoinPoint; 8 | import org.aspectj.lang.annotation.Around; 9 | import org.aspectj.lang.annotation.Aspect; 10 | import org.aspectj.lang.reflect.MethodSignature; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.core.env.Environment; 13 | import org.springframework.stereotype.Component; 14 | 15 | import java.lang.annotation.Annotation; 16 | import java.lang.reflect.Method; 17 | import java.time.OffsetDateTime; 18 | import java.util.concurrent.ConcurrentHashMap; 19 | import java.util.concurrent.ConcurrentMap; 20 | 21 | import static io.bitdive.parent.message_producer.MessageService.sendMessageStompConsumer; 22 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.getaNullThrowable; 23 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.paramConvert; 24 | 25 | @Aspect 26 | @Component 27 | public class StompMessageMappingAspect { 28 | 29 | @Autowired 30 | private Environment environment; 31 | 32 | private final ConcurrentMap mappingCache = new ConcurrentHashMap<>(); 33 | 34 | @Around("@annotation(org.springframework.messaging.handler.annotation.MessageMapping)") 35 | public Object aroundMessageMapping(ProceedingJoinPoint joinPoint) throws Throwable { 36 | if (LoggerStatusContent.getEnabledProfile()) return joinPoint.proceed(); 37 | ContextManager.createNewRequest(); 38 | String uuidMessage = UuidCreator.getTimeBased().toString(); 39 | Throwable thrown = null; 40 | MethodSignature methodSig = (MethodSignature) joinPoint.getSignature(); 41 | OffsetDateTime startTime = OffsetDateTime.now(); 42 | 43 | Method method = methodSig.getMethod(); 44 | CachedMappingInfo cachedInfo = mappingCache.get(method); 45 | if (cachedInfo == null) { 46 | cachedInfo = resolveMessageMapping(method); 47 | mappingCache.put(method, cachedInfo); 48 | } 49 | 50 | ContextManager.setMethodCallContextQueue(uuidMessage); 51 | ContextManager.setClassInpointName(methodSig.getDeclaringTypeName()); 52 | ContextManager.setMethodInpointName(methodSig.getName()); 53 | ContextManager.setMessageInpointId(uuidMessage); 54 | Object retVal; 55 | try { 56 | retVal = joinPoint.proceed(); 57 | } catch (Throwable t) { 58 | thrown = t; 59 | throw t; 60 | } finally { 61 | String destination = cachedInfo.getDestination(); 62 | 63 | sendMessageStompConsumer( 64 | uuidMessage, 65 | methodSig.getDeclaringTypeName(), 66 | methodSig.getName(), 67 | ContextManager.getTraceId(), 68 | ContextManager.getSpanId(), 69 | startTime, 70 | OffsetDateTime.now(), 71 | destination, 72 | ReflectionUtils.objectToString(paramConvert(joinPoint.getArgs(), methodSig.getMethod())), 73 | getaNullThrowable(thrown), 74 | true, 75 | ContextManager.getMethodInpointName(), 76 | ContextManager.getMessageInpointId(), 77 | ContextManager.getClassInpointName() 78 | ); 79 | } 80 | return retVal; 81 | } 82 | 83 | private CachedMappingInfo resolveMessageMapping(Method method) { 84 | Annotation[] annotations = method.getDeclaredAnnotations(); 85 | for (Annotation annotation : annotations) { 86 | if (annotation.annotationType().getName().equals("org.springframework.messaging.handler.annotation.MessageMapping")) { 87 | try { 88 | Method valueMethod = annotation.annotationType().getMethod("value"); 89 | String[] values = (String[]) valueMethod.invoke(annotation); 90 | for (int i = 0; i < values.length; i++) values[i] = environment.resolvePlaceholders(values[i]); 91 | String destination = String.join(",", values); 92 | return new CachedMappingInfo(destination); 93 | } catch (Exception ignore) { 94 | return new CachedMappingInfo(""); 95 | } 96 | } 97 | } 98 | return new CachedMappingInfo(""); 99 | } 100 | 101 | private static class CachedMappingInfo { 102 | private final String destination; 103 | 104 | private CachedMappingInfo(String destination) { 105 | this.destination = destination; 106 | } 107 | 108 | public String getDestination() { 109 | return destination; 110 | } 111 | } 112 | } 113 | 114 | 115 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/parserConfig/ProfilingConfig.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.parserConfig; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import org.apache.commons.lang3.ObjectUtils; 6 | 7 | import java.util.*; 8 | import java.util.stream.Collectors; 9 | import java.util.stream.Stream; 10 | 11 | @Getter 12 | @Setter 13 | public class ProfilingConfig { 14 | 15 | private List notWorkWithSpringProfiles; 16 | 17 | private ApplicationConfig application; 18 | private List monitoringConfigs = new ArrayList<>(); 19 | private MonitoringConfig monitoring; 20 | private AuthorisationConfig authorisation; 21 | 22 | public void detectActualConfig(String[] profileNames) { 23 | if (ObjectUtils.isNotEmpty(profileNames)) { 24 | Set activeProfileSet = Arrays.stream(profileNames).collect(Collectors.toSet()); 25 | 26 | List monitoringFilterProfile = 27 | monitoringConfigs.stream().filter(monitoringConfig -> { 28 | Set activeProfileSetLocal = new HashSet<>(activeProfileSet); 29 | Set monitoringProfileSet = Optional.ofNullable(monitoringConfig.getForSpringProfile()) 30 | .map(Arrays::stream) 31 | .orElseGet(Stream::empty) 32 | .collect(Collectors.toSet()); 33 | ; 34 | activeProfileSetLocal.retainAll(monitoringProfileSet); 35 | return !activeProfileSetLocal.isEmpty(); 36 | } 37 | ).collect(Collectors.toList()); 38 | if (monitoringFilterProfile.size() > 1) { 39 | throw new IllegalArgumentException("profile Name must not contain more than one monitoring profile"); 40 | } 41 | if (monitoringFilterProfile.isEmpty()) { 42 | throw new IllegalArgumentException("monitoring settings cannot be empty for active profile"); 43 | } 44 | monitoring = monitoringFilterProfile.get(0); 45 | } else { 46 | List monitoringFilterProfile = monitoringConfigs.stream() 47 | .filter(monitoringConfig -> monitoringConfig.getForSpringProfile() == null) 48 | .collect(Collectors.toList()); 49 | if (monitoringFilterProfile.isEmpty()) { 50 | throw new IllegalArgumentException("monitoring settings cannot be empty for active profile"); 51 | } 52 | monitoring = monitoringFilterProfile.get(0); 53 | } 54 | 55 | 56 | } 57 | 58 | @Getter 59 | @Setter 60 | public static class MonitoringConfig { 61 | private LogLevelEnum logLevel; 62 | private Boolean monitoringArgumentMethod; 63 | private Boolean monitoringReturnMethod; 64 | private Boolean monitoringStaticMethod; 65 | private Boolean monitoringOnlySpringComponent; 66 | private MonitoringSendFilesConfig sendFiles; 67 | private MonitoringDataFile dataFile; 68 | private Serialization serialization; 69 | private boolean enabled = true; 70 | 71 | private String[] forSpringProfile; 72 | 73 | @Getter 74 | @Setter 75 | public static class Serialization { 76 | private String[] excludedPackages; 77 | private Integer maxElementCollection; 78 | } 79 | 80 | @Getter 81 | @Setter 82 | public static class MonitoringDataFile { 83 | private String path; 84 | private Integer timerConvertForSend; 85 | private Integer fileStorageTime; 86 | 87 | } 88 | 89 | @Getter 90 | @Setter 91 | public static class MonitoringSendFilesConfig { 92 | private ServerConsumerConfig serverConsumer; 93 | private Long schedulerTimer; 94 | private VaultConfig vault; 95 | 96 | @Getter 97 | @Setter 98 | public static class ServerConsumerConfig { 99 | private String url; 100 | private ProxyConfig proxy; 101 | 102 | 103 | public boolean isSSLSend() { 104 | return url.toLowerCase().contains("https"); 105 | } 106 | 107 | @Getter 108 | @Setter 109 | public static class ProxyConfig { 110 | private String host; 111 | private Integer port; 112 | private String username; 113 | private String password; 114 | } 115 | } 116 | 117 | @Getter 118 | @Setter 119 | public static class VaultConfig { 120 | private String url; 121 | private String token; 122 | } 123 | } 124 | } 125 | 126 | @Getter 127 | @Setter 128 | public static class ApplicationConfig { 129 | private String moduleName; 130 | private String serviceName; 131 | private String[] packedScanner; 132 | } 133 | 134 | @Getter 135 | @Setter 136 | public static class AuthorisationConfig { 137 | private String token; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.bitdive 9 | bitdive-producer-spring-3 10 | 1.3.4 11 | producer-for-spring-3 12 | 13 | 14 | org.springframework.boot 15 | spring-boot-starter-parent 16 | 3.2.0 17 | 18 | 19 | 20 | 21 | 22 | BitDive.io Agent Proprietary License 23 | https://bitdive.io/docs/license 24 | repo 25 | 26 | 27 | 28 | library is a module for the system for collecting profiling information for spring 3 29 | 30 | bitdive.io 31 | 32 | https://github.com/username/my-project 33 | scm:git:git://github.com/username/my-project.git 34 | scm:git:ssh://github.com/username/my-project.git 35 | 36 | 37 | 38 | 39 | FrolikovEA 40 | ef@bitdive.io 41 | 42 | 43 | 44 | 45 | 46 | org.apache.logging.log4j 47 | log4j-core 48 | 49 | 50 | 51 | org.apache.logging.log4j 52 | log4j-api 53 | 54 | 55 | 56 | org.aspectj 57 | aspectjweaver 58 | 59 | 60 | 61 | org.springframework 62 | spring-context 63 | 64 | 65 | 66 | org.springframework.boot 67 | spring-boot-autoconfigure 68 | 69 | 70 | 71 | org.projectlombok 72 | lombok 73 | 74 | 75 | 76 | org.yaml 77 | snakeyaml 78 | 2.2 79 | 80 | 81 | 82 | io.bitdive 83 | java-producer-parent 84 | 1.3.4 85 | 86 | 87 | 88 | io.micrometer 89 | micrometer-core 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | org.apache.maven.plugins 98 | maven-gpg-plugin 99 | 1.6 100 | 101 | 102 | sign-artifacts 103 | verify 104 | 105 | sign 106 | 107 | 108 | 109 | 110 | C:\Program Files (x86)\GnuPG\bin\gpg.exe 111 | 112 | 113 | 114 | 115 | org.sonatype.central 116 | central-publishing-maven-plugin 117 | 0.6.0 118 | true 119 | 120 | central 121 | 122 | 123 | 124 | 125 | org.apache.maven.plugins 126 | maven-source-plugin 127 | 3.2.1 128 | 129 | 130 | attach-sources 131 | 132 | jar 133 | 134 | 135 | 136 | 137 | 138 | 139 | org.apache.maven.plugins 140 | maven-javadoc-plugin 141 | 3.2.0 142 | 143 | 144 | attach-javadocs 145 | 146 | jar 147 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-2.7/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.bitdive 9 | bitdive-producer-spring-2 10 | 1.3.4 11 | producer-for-spring-2 12 | 13 | org.springframework.boot 14 | spring-boot-starter-parent 15 | 2.7.14 16 | 17 | 18 | 19 | 20 | 21 | 22 | BitDive.io Agent Proprietary License 23 | https://bitdive.io/docs/license 24 | repo 25 | 26 | 27 | 28 | library is a module for the system for collecting profiling information for spring 2 29 | 30 | bitdive.io 31 | 32 | https://github.com/username/my-project 33 | scm:git:git://github.com/username/my-project.git 34 | scm:git:ssh://github.com/username/my-project.git 35 | 36 | 37 | 38 | 39 | FrolikovEA 40 | ef@bitdive.io 41 | 42 | 43 | 44 | 45 | 46 | 47 | org.apache.logging.log4j 48 | log4j-core 49 | 50 | 51 | 52 | org.apache.logging.log4j 53 | log4j-api 54 | 55 | 56 | 57 | org.aspectj 58 | aspectjweaver 59 | 60 | 61 | 62 | org.springframework 63 | spring-context 64 | 65 | 66 | 67 | org.springframework.boot 68 | spring-boot-autoconfigure 69 | 70 | 71 | 72 | org.projectlombok 73 | lombok 74 | 75 | 76 | 77 | org.yaml 78 | snakeyaml 79 | 2.2 80 | 81 | 82 | 83 | io.bitdive 84 | java-producer-parent 85 | 1.3.4 86 | 87 | 88 | 89 | io.micrometer 90 | micrometer-core 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | org.apache.maven.plugins 100 | maven-gpg-plugin 101 | 1.6 102 | 103 | 104 | sign-artifacts 105 | verify 106 | 107 | sign 108 | 109 | 110 | 111 | 112 | C:\Program Files (x86)\GnuPG\bin\gpg.exe 113 | 114 | 115 | 116 | 117 | org.sonatype.central 118 | central-publishing-maven-plugin 119 | 0.6.0 120 | true 121 | 122 | central 123 | 124 | 125 | 126 | 127 | org.apache.maven.plugins 128 | maven-source-plugin 129 | 3.2.1 130 | 131 | 132 | attach-sources 133 | 134 | jar 135 | 136 | 137 | 138 | 139 | 140 | 141 | org.apache.maven.plugins 142 | maven-javadoc-plugin 143 | 3.2.0 144 | 145 | 146 | attach-javadocs 147 | 148 | jar 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/src/main/java/io/bitdive/aspect/KafkaListenerAspect.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.aspect; 2 | 3 | import com.github.f4b6a3.uuid.UuidCreator; 4 | import io.bitdive.parent.trasirovka.agent.utils.ContextManager; 5 | import io.bitdive.parent.trasirovka.agent.utils.KafkaAgentStorage; 6 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 7 | import io.bitdive.parent.trasirovka.agent.utils.ReflectionUtils; 8 | import lombok.Getter; 9 | import org.aspectj.lang.ProceedingJoinPoint; 10 | import org.aspectj.lang.annotation.Around; 11 | import org.aspectj.lang.annotation.Aspect; 12 | import org.aspectj.lang.reflect.MethodSignature; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.core.env.Environment; 15 | import org.springframework.stereotype.Component; 16 | 17 | import java.lang.annotation.Annotation; 18 | import java.lang.reflect.Method; 19 | import java.time.OffsetDateTime; 20 | import java.util.concurrent.ConcurrentHashMap; 21 | import java.util.concurrent.ConcurrentMap; 22 | 23 | import static io.bitdive.parent.message_producer.MessageService.sendMessageKafkaConsumer; 24 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.getaNullThrowable; 25 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.paramConvert; 26 | 27 | @Aspect 28 | @Component 29 | public class KafkaListenerAspect { 30 | 31 | @Autowired 32 | private Environment environment; 33 | 34 | private final ConcurrentMap kafkaListenerCache = new ConcurrentHashMap<>(); 35 | 36 | @Around("@annotation(org.springframework.kafka.annotation.KafkaListener)") 37 | public Object aroundKafkaListener(ProceedingJoinPoint joinPoint) throws Throwable { 38 | if (LoggerStatusContent.getEnabledProfile()) return joinPoint.proceed(); 39 | ContextManager.createNewRequest(); 40 | String uuidMessage = UuidCreator.getTimeBased().toString(); 41 | Throwable thrown = null; 42 | MethodSignature methodSig = (MethodSignature) joinPoint.getSignature(); 43 | OffsetDateTime startTime = OffsetDateTime.now(); 44 | String topicName = ""; 45 | String groupName = ""; 46 | 47 | Method method = methodSig.getMethod(); 48 | 49 | CachedKafkaInfo cachedInfo = kafkaListenerCache.get(method); 50 | if (cachedInfo != null) { 51 | topicName = cachedInfo.getTopicName(); 52 | groupName = cachedInfo.getGroupName(); 53 | } else { 54 | Annotation[] annotations = method.getDeclaredAnnotations(); 55 | for (Annotation annotation : annotations) { 56 | if (annotation.annotationType().getName().equals("org.springframework.kafka.annotation.KafkaListener")) { 57 | try { 58 | Method topicsMethod = annotation.annotationType().getMethod("topics"); 59 | String[] topics = (String[]) topicsMethod.invoke(annotation); 60 | 61 | Method groupIdMethod = annotation.annotationType().getMethod("groupId"); 62 | String groupId = (String) groupIdMethod.invoke(annotation); 63 | 64 | for (int i = 0; i < topics.length; i++) { 65 | topics[i] = environment.resolvePlaceholders(topics[i]); 66 | } 67 | groupId = environment.resolvePlaceholders(groupId); 68 | 69 | topicName = String.join(",", topics); 70 | groupName = groupId; 71 | 72 | cachedInfo = new CachedKafkaInfo(topicName, groupName); 73 | kafkaListenerCache.put(method, cachedInfo); 74 | } catch (Exception e) { 75 | if (LoggerStatusContent.isErrorsOrDebug()) 76 | System.err.println("aroundKafkaListener ERROR: " + e.getMessage()); 77 | } 78 | break; 79 | } 80 | } 81 | } 82 | ContextManager.setMethodCallContextQueue(uuidMessage); 83 | ContextManager.setMethodInpointName(methodSig.getName()); 84 | ContextManager.setClassInpointName(methodSig.getDeclaringTypeName()); 85 | ContextManager.setMessageInpointId(uuidMessage); 86 | Object retVal; 87 | try { 88 | retVal = joinPoint.proceed(); 89 | } catch (Throwable t) { 90 | thrown = t; 91 | throw t; 92 | } finally { 93 | 94 | sendMessageKafkaConsumer( 95 | uuidMessage, 96 | methodSig.getDeclaringTypeName(), 97 | methodSig.getName(), 98 | ContextManager.getTraceId(), 99 | ContextManager.getSpanId(), 100 | startTime, 101 | OffsetDateTime.now(), 102 | true, 103 | ReflectionUtils.objectToString(paramConvert(joinPoint.getArgs(), method)), 104 | topicName, 105 | groupName, 106 | KafkaAgentStorage.getBootstrap(), 107 | getaNullThrowable(thrown), 108 | ContextManager.getMethodInpointName(), 109 | ContextManager.getMessageInpointId(), 110 | ContextManager.getClassInpointName() 111 | ); 112 | } 113 | return retVal; 114 | } 115 | 116 | @Getter 117 | private static class CachedKafkaInfo { 118 | private final String topicName; 119 | private final String groupName; 120 | 121 | public CachedKafkaInfo(String topicName, String groupName) { 122 | this.topicName = topicName; 123 | this.groupName = groupName; 124 | } 125 | 126 | } 127 | 128 | } -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-2.7/src/main/java/io/bitdive/aspect/KafkaListenerAspect.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.aspect; 2 | 3 | import com.github.f4b6a3.uuid.UuidCreator; 4 | import io.bitdive.parent.trasirovka.agent.utils.ContextManager; 5 | import io.bitdive.parent.trasirovka.agent.utils.KafkaAgentStorage; 6 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 7 | import io.bitdive.parent.trasirovka.agent.utils.ReflectionUtils; 8 | import lombok.Getter; 9 | import org.aspectj.lang.ProceedingJoinPoint; 10 | import org.aspectj.lang.annotation.Around; 11 | import org.aspectj.lang.annotation.Aspect; 12 | import org.aspectj.lang.reflect.MethodSignature; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.core.env.Environment; 15 | import org.springframework.stereotype.Component; 16 | 17 | import java.lang.annotation.Annotation; 18 | import java.lang.reflect.Method; 19 | import java.time.OffsetDateTime; 20 | import java.util.concurrent.ConcurrentHashMap; 21 | import java.util.concurrent.ConcurrentMap; 22 | 23 | import static io.bitdive.parent.message_producer.MessageService.sendMessageKafkaConsumer; 24 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.getaNullThrowable; 25 | import static io.bitdive.parent.trasirovka.agent.utils.DataUtils.paramConvert; 26 | 27 | @Aspect 28 | @Component 29 | public class KafkaListenerAspect { 30 | 31 | @Autowired 32 | private Environment environment; 33 | 34 | private final ConcurrentMap kafkaListenerCache = new ConcurrentHashMap<>(); 35 | 36 | @Around("@annotation(org.springframework.kafka.annotation.KafkaListener)") 37 | public Object aroundKafkaListener(ProceedingJoinPoint joinPoint) throws Throwable { 38 | if (LoggerStatusContent.getEnabledProfile()) return joinPoint.proceed(); 39 | ContextManager.createNewRequest(); 40 | String uuidMessage = UuidCreator.getTimeBased().toString(); 41 | Throwable thrown = null; 42 | MethodSignature methodSig = (MethodSignature) joinPoint.getSignature(); 43 | OffsetDateTime startTime = OffsetDateTime.now(); 44 | String topicName = ""; 45 | String groupName = ""; 46 | 47 | Method method = methodSig.getMethod(); 48 | 49 | CachedKafkaInfo cachedInfo = kafkaListenerCache.get(method); 50 | if (cachedInfo != null) { 51 | topicName = cachedInfo.getTopicName(); 52 | groupName = cachedInfo.getGroupName(); 53 | } else { 54 | Annotation[] annotations = method.getDeclaredAnnotations(); 55 | for (Annotation annotation : annotations) { 56 | if (annotation.annotationType().getName().equals("org.springframework.kafka.annotation.KafkaListener")) { 57 | try { 58 | Method topicsMethod = annotation.annotationType().getMethod("topics"); 59 | String[] topics = (String[]) topicsMethod.invoke(annotation); 60 | 61 | Method groupIdMethod = annotation.annotationType().getMethod("groupId"); 62 | String groupId = (String) groupIdMethod.invoke(annotation); 63 | 64 | for (int i = 0; i < topics.length; i++) { 65 | topics[i] = environment.resolvePlaceholders(topics[i]); 66 | } 67 | groupId = environment.resolvePlaceholders(groupId); 68 | 69 | topicName = String.join(",", topics); 70 | groupName = groupId; 71 | 72 | cachedInfo = new CachedKafkaInfo(topicName, groupName); 73 | kafkaListenerCache.put(method, cachedInfo); 74 | } catch (Exception e) { 75 | if (LoggerStatusContent.isErrorsOrDebug()) 76 | System.err.println("aroundKafkaListener ERROR: " + e.getMessage()); 77 | } 78 | break; 79 | } 80 | } 81 | } 82 | ContextManager.setMethodCallContextQueue(uuidMessage); 83 | ContextManager.setClassInpointName(methodSig.getDeclaringTypeName()); 84 | ContextManager.setMethodInpointName(methodSig.getName()); 85 | ContextManager.setMessageInpointId(uuidMessage); 86 | Object retVal; 87 | try { 88 | retVal = joinPoint.proceed(); 89 | } catch (Throwable t) { 90 | thrown = t; 91 | throw t; 92 | } finally { 93 | 94 | 95 | sendMessageKafkaConsumer( 96 | uuidMessage, 97 | methodSig.getDeclaringTypeName(), 98 | methodSig.getName(), 99 | ContextManager.getTraceId(), 100 | ContextManager.getSpanId(), 101 | startTime, 102 | OffsetDateTime.now(), 103 | true, 104 | ReflectionUtils.objectToString(paramConvert(joinPoint.getArgs(), method)), 105 | topicName, 106 | groupName, 107 | KafkaAgentStorage.getBootstrap(), 108 | getaNullThrowable(thrown), 109 | ContextManager.getMethodInpointName(), 110 | ContextManager.getMessageInpointId(), 111 | ContextManager.getClassInpointName() 112 | ); 113 | } 114 | return retVal; 115 | } 116 | 117 | @Getter 118 | private static class CachedKafkaInfo { 119 | private final String topicName; 120 | private final String groupName; 121 | 122 | public CachedKafkaInfo(String topicName, String groupName) { 123 | this.topicName = topicName; 124 | this.groupName = groupName; 125 | } 126 | 127 | } 128 | 129 | } -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/utils/CallableStatementParser.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.utils; 2 | 3 | import java.lang.reflect.Field; 4 | import java.sql.CallableStatement; 5 | import java.util.regex.Matcher; 6 | import java.util.regex.Pattern; 7 | 8 | public class CallableStatementParser { 9 | 10 | 11 | private static final Pattern CALL_PATTERN = 12 | Pattern.compile("(?i)\\{\\s*call\\s+([^(]+)\\(([^)]*)\\)\\s*}"); 13 | 14 | public static String getCallableSQL(CallableStatement stmt) { 15 | if (stmt == null) return "NULL"; 16 | 17 | String sql = tryMSSQL(stmt); 18 | if (sql != null) return sql; 19 | 20 | sql = tryMySQL(stmt); 21 | if (sql != null) return sql; 22 | 23 | sql = tryOracle(stmt); 24 | if (sql != null) return sql; 25 | 26 | sql = tryPostgreSQL(stmt); 27 | if (sql != null) return sql; 28 | 29 | return parseByToString(stmt); 30 | } 31 | 32 | 33 | private static String tryMSSQL(CallableStatement stmt) { 34 | String className = stmt.getClass().getName(); 35 | if (!className.startsWith("com.microsoft.sqlserver.jdbc")) { 36 | return null; 37 | } 38 | 39 | try { 40 | Object sqlObj = getObjectMSSQL(stmt, "preparedSQL"); 41 | 42 | if (sqlObj == null) { 43 | sqlObj = getObjectMSSQL(stmt, "userSQL"); 44 | if (sqlObj == null) return null; 45 | } 46 | 47 | String sqlString = sqlObj.toString(); 48 | return parseCallString(sqlString); 49 | 50 | } catch (Exception e) { 51 | return null; 52 | } 53 | } 54 | 55 | private static Object getObjectMSSQL(CallableStatement stmt, String fieldName) throws IllegalAccessException { 56 | Field psField = findFieldRecursively(stmt.getClass(), fieldName); 57 | if (psField == null) { 58 | return null; 59 | } 60 | psField.setAccessible(true); 61 | 62 | Object sqlObj = psField.get(stmt); 63 | return sqlObj; 64 | } 65 | 66 | private static Field findFieldRecursively(Class clazz, String fieldName) { 67 | Class current = clazz; 68 | while (current != null) { 69 | try { 70 | return current.getDeclaredField(fieldName); 71 | } catch (NoSuchFieldException e) { 72 | // Переходим к родителю 73 | current = current.getSuperclass(); 74 | } 75 | } 76 | // Не нашли 77 | return null; 78 | } 79 | 80 | private static String tryMySQL(CallableStatement stmt) { 81 | String className = stmt.getClass().getName(); 82 | if (!className.startsWith("com.mysql.cj.jdbc")) { 83 | return null; 84 | } 85 | try { 86 | Field procNameField = stmt.getClass().getDeclaredField("procName"); 87 | procNameField.setAccessible(true); 88 | Object procNameObj = procNameField.get(stmt); 89 | String procName = (procNameObj != null) ? procNameObj.toString() : "UNKNOWN_PROCEDURE"; 90 | 91 | 92 | String params = ""; 93 | try { 94 | Field paramsField = stmt.getClass().getDeclaredField("parameters"); 95 | paramsField.setAccessible(true); 96 | Object parametersObj = paramsField.get(stmt); 97 | params = (parametersObj != null) ? parametersObj.toString() : ""; 98 | } catch (NoSuchFieldException ignored) { 99 | 100 | } 101 | 102 | return buildCallString(procName, params); 103 | } catch (NoSuchFieldException | IllegalAccessException e) { 104 | return null; 105 | } 106 | } 107 | 108 | 109 | private static String tryOracle(CallableStatement stmt) { 110 | String className = stmt.getClass().getName(); 111 | if (!className.startsWith("oracle.jdbc")) { 112 | return null; 113 | } 114 | try { 115 | Field sqlField = stmt.getClass().getDeclaredField("sqlObject"); 116 | sqlField.setAccessible(true); 117 | Object sqlObj = sqlField.get(stmt); 118 | if (sqlObj != null) { 119 | 120 | String sqlString = sqlObj.toString(); 121 | 122 | return parseCallString(sqlString); 123 | } 124 | } catch (NoSuchFieldException | IllegalAccessException e) { 125 | } 126 | return null; 127 | } 128 | 129 | 130 | private static String tryPostgreSQL(CallableStatement stmt) { 131 | 132 | String className = stmt.getClass().getName(); 133 | if (!className.startsWith("org.postgresql.")) { 134 | return null; 135 | } 136 | try { 137 | Field f = stmt.getClass().getDeclaredField("preparedQuery"); 138 | f.setAccessible(true); 139 | Object queryObj = f.get(stmt); 140 | if (queryObj != null) { 141 | String queryStr = queryObj.toString(); 142 | 143 | return parseCallString(queryStr); 144 | } 145 | } catch (Exception e) { 146 | 147 | } 148 | return null; 149 | } 150 | 151 | 152 | private static String parseCallString(String callString) { 153 | if (callString == null) return null; 154 | Matcher m = CALL_PATTERN.matcher(callString); 155 | if (m.find()) { 156 | String procName = m.group(1).trim(); 157 | String params = m.group(2).trim(); 158 | return buildCallString(procName, params); 159 | } 160 | 161 | return callString; 162 | } 163 | 164 | 165 | private static String parseByToString(CallableStatement stmt) { 166 | String ts = stmt.toString(); 167 | return parseCallString(ts); 168 | } 169 | 170 | private static String buildCallString(String procName, String params) { 171 | 172 | if (params == null || params.isEmpty()) { 173 | return "CALL " + procName; 174 | } 175 | return "CALL " + procName + "(" + params + ")"; 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-2.7/src/main/java/io/bitdive/ByteBuddyAgentInitializer.java: -------------------------------------------------------------------------------- 1 | package io.bitdive; 2 | 3 | import io.bitdive.jvm_metrics.GenerateJvmMetrics; 4 | import io.bitdive.parent.init.MonitoringStarting; 5 | import io.bitdive.parent.message_producer.LibraryLoggerConfig; 6 | import io.bitdive.parent.parserConfig.ConfigForServiceDTO; 7 | import io.bitdive.parent.parserConfig.YamlParserConfig; 8 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 9 | import io.bitdive.parent.utils.ByteBuddyConfigLoader; 10 | import io.bitdive.parent.utils.LibraryVersionBitDive; 11 | import org.springframework.context.ApplicationContextInitializer; 12 | import org.springframework.context.ConfigurableApplicationContext; 13 | import org.springframework.core.env.ConfigurableEnvironment; 14 | 15 | import java.util.Arrays; 16 | import java.util.HashSet; 17 | import java.util.Set; 18 | import java.util.concurrent.Executors; 19 | import java.util.concurrent.ScheduledExecutorService; 20 | import java.util.concurrent.TimeUnit; 21 | import java.util.stream.Collectors; 22 | 23 | public class ByteBuddyAgentInitializer implements ApplicationContextInitializer { 24 | private static boolean initializeAgent = false; 25 | 26 | private static ScheduledExecutorService scheduler; 27 | 28 | @Override 29 | public void initialize(ConfigurableApplicationContext applicationContext) { 30 | try { 31 | ConfigurableEnvironment env = applicationContext.getEnvironment(); 32 | String[] activeProfiles = env.getActiveProfiles(); 33 | 34 | if (initializeAgent) { 35 | return; 36 | } 37 | 38 | if (isTestEnvironment()) { 39 | YamlParserConfig.setWork(false); 40 | return; 41 | } 42 | 43 | ConfigForServiceDTO configForServiceDTO = ByteBuddyConfigLoader.load(); 44 | 45 | scheduler = Executors.newSingleThreadScheduledExecutor(r -> { 46 | Thread t = new Thread(r, "minute-task"); 47 | t.setDaemon(true); 48 | return t; 49 | }); 50 | 51 | final ConfigForServiceDTO configForServiceDTOFinal = configForServiceDTO; 52 | 53 | Runnable task = () -> { 54 | try { 55 | if (initializeAgent) { 56 | YamlParserConfig.setWork(false); 57 | YamlParserConfig.loadConfig(configForServiceDTOFinal); 58 | YamlParserConfig.getProfilingConfig().detectActualConfig(activeProfiles); 59 | 60 | if (activeProfiles.length > 0) { 61 | YamlParserConfig.getProfilingConfig().getApplication().setModuleName( 62 | YamlParserConfig.getProfilingConfig().getApplication().getModuleName() + "-" + 63 | String.join("-", activeProfiles) 64 | ); 65 | } 66 | 67 | LibraryLoggerConfig.init(); 68 | GenerateJvmMetrics.init(); 69 | if (LoggerStatusContent.isDebug()) { 70 | System.err.println("Minute task reload config "); 71 | } 72 | YamlParserConfig.setWork(true); 73 | } 74 | } catch (Throwable ex) { 75 | } 76 | }; 77 | 78 | 79 | scheduler.scheduleAtFixedRate(task, 1, 1, TimeUnit.MINUTES); 80 | 81 | YamlParserConfig.loadConfig(configForServiceDTO); 82 | YamlParserConfig.setLibraryVersion(LibraryVersionBitDive.version); 83 | 84 | 85 | if (YamlParserConfig.getProfilingConfig().getNotWorkWithSpringProfiles() != null && 86 | !YamlParserConfig.getProfilingConfig().getNotWorkWithSpringProfiles().isEmpty()) { 87 | Set activeProfileSet = Arrays.stream(activeProfiles).collect(Collectors.toSet()); 88 | Set notWorkProfileSet = new HashSet<>(YamlParserConfig.getProfilingConfig().getNotWorkWithSpringProfiles()); 89 | 90 | activeProfileSet.retainAll(notWorkProfileSet); 91 | if (!activeProfileSet.isEmpty()) { 92 | initializeAgent = true; 93 | YamlParserConfig.setWork(false); 94 | return; 95 | } 96 | 97 | 98 | } 99 | 100 | YamlParserConfig.getProfilingConfig().detectActualConfig(activeProfiles); 101 | if (LoggerStatusContent.isDebug()) { 102 | System.out.println("ByteBuddyAgentInitializer initialize start version: " + YamlParserConfig.getLibraryVersion()); 103 | } 104 | 105 | 106 | if (activeProfiles.length > 0) { 107 | YamlParserConfig.getProfilingConfig().getApplication().setModuleName( 108 | YamlParserConfig.getProfilingConfig().getApplication().getModuleName() + "-" + 109 | String.join("-", activeProfiles) 110 | ); 111 | } 112 | 113 | 114 | LibraryLoggerConfig.init(); 115 | MonitoringStarting.init(); 116 | GenerateJvmMetrics.init(); 117 | 118 | initializeAgent = true; 119 | YamlParserConfig.setWork(true); 120 | 121 | } catch (Exception e) { 122 | if (LoggerStatusContent.isErrorsOrDebug()) { 123 | initializeAgent = true; 124 | YamlParserConfig.setWork(false); 125 | System.out.println("ByteBuddyAgentInitializer initialize error " + e.getMessage()); 126 | } 127 | } 128 | } 129 | 130 | private boolean isTestEnvironment() { 131 | try { 132 | if ("test".equalsIgnoreCase(System.getProperty("env")) || 133 | "test".equalsIgnoreCase(System.getenv("ENV")) 134 | ) return true; 135 | Class.forName("org.junit.jupiter.api.Test"); 136 | return true; 137 | } catch (ClassNotFoundException e) { 138 | return false; 139 | } 140 | } 141 | } -------------------------------------------------------------------------------- /perf-monitoring-producer-spring-3/src/main/java/io/bitdive/ByteBuddyAgentInitializer.java: -------------------------------------------------------------------------------- 1 | package io.bitdive; 2 | 3 | 4 | import io.bitdive.jvm_metrics.GenerateJvmMetrics; 5 | import io.bitdive.parent.init.MonitoringStarting; 6 | import io.bitdive.parent.message_producer.LibraryLoggerConfig; 7 | import io.bitdive.parent.parserConfig.ConfigForServiceDTO; 8 | import io.bitdive.parent.parserConfig.YamlParserConfig; 9 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 10 | import io.bitdive.parent.utils.ByteBuddyConfigLoader; 11 | import io.bitdive.parent.utils.LibraryVersionBitDive; 12 | import org.springframework.context.ApplicationContextInitializer; 13 | import org.springframework.context.ConfigurableApplicationContext; 14 | import org.springframework.core.env.ConfigurableEnvironment; 15 | 16 | import java.util.Arrays; 17 | import java.util.HashSet; 18 | import java.util.Set; 19 | import java.util.concurrent.Executors; 20 | import java.util.concurrent.ScheduledExecutorService; 21 | import java.util.concurrent.TimeUnit; 22 | import java.util.stream.Collectors; 23 | 24 | public class ByteBuddyAgentInitializer implements ApplicationContextInitializer { 25 | private static boolean initializeAgent = false; 26 | 27 | private static ScheduledExecutorService scheduler; 28 | 29 | @Override 30 | public void initialize(ConfigurableApplicationContext applicationContext) { 31 | try { 32 | ConfigurableEnvironment env = applicationContext.getEnvironment(); 33 | String[] activeProfiles = env.getActiveProfiles(); 34 | 35 | if (initializeAgent) { 36 | return; 37 | } 38 | 39 | if (isTestEnvironment()) { 40 | YamlParserConfig.setWork(false); 41 | return; 42 | } 43 | ConfigForServiceDTO configForServiceDTO = ByteBuddyConfigLoader.load(); 44 | 45 | scheduler = Executors.newSingleThreadScheduledExecutor(r -> { 46 | Thread t = new Thread(r, "minute-task"); 47 | t.setDaemon(true); 48 | return t; 49 | }); 50 | 51 | final ConfigForServiceDTO configForServiceDTOFinal = configForServiceDTO; 52 | 53 | Runnable task = () -> { 54 | try { 55 | if (initializeAgent || YamlParserConfig.isWork()) { 56 | YamlParserConfig.setWork(false); 57 | YamlParserConfig.loadConfig(configForServiceDTOFinal); 58 | YamlParserConfig.getProfilingConfig().detectActualConfig(activeProfiles); 59 | if (activeProfiles.length > 0) { 60 | YamlParserConfig.getProfilingConfig().getApplication().setModuleName( 61 | YamlParserConfig.getProfilingConfig().getApplication().getModuleName() + "-" + 62 | String.join("-", activeProfiles) 63 | ); 64 | } 65 | LibraryLoggerConfig.init(); 66 | GenerateJvmMetrics.init(); 67 | if (LoggerStatusContent.isDebug()) { 68 | System.err.println("Minute task reload config "); 69 | } 70 | YamlParserConfig.setWork(true); 71 | } 72 | } catch (Throwable ex) { 73 | } 74 | }; 75 | 76 | 77 | scheduler.scheduleAtFixedRate(task, 1, 1, TimeUnit.MINUTES); 78 | 79 | YamlParserConfig.loadConfig(configForServiceDTO); 80 | YamlParserConfig.setLibraryVersion(LibraryVersionBitDive.version); 81 | 82 | 83 | if (YamlParserConfig.getProfilingConfig().getNotWorkWithSpringProfiles() != null && 84 | !YamlParserConfig.getProfilingConfig().getNotWorkWithSpringProfiles().isEmpty()) { 85 | Set activeProfileSet = Arrays.stream(activeProfiles).collect(Collectors.toSet()); 86 | Set notWorkProfileSet = new HashSet<>(YamlParserConfig.getProfilingConfig().getNotWorkWithSpringProfiles()); 87 | 88 | activeProfileSet.retainAll(notWorkProfileSet); 89 | if (!activeProfileSet.isEmpty()) { 90 | initializeAgent = true; 91 | YamlParserConfig.setWork(false); 92 | return; 93 | } 94 | } 95 | 96 | YamlParserConfig.getProfilingConfig().detectActualConfig(activeProfiles); 97 | if (LoggerStatusContent.isDebug()) { 98 | System.out.println("ByteBuddyAgentInitializer initialize start version: " + YamlParserConfig.getLibraryVersion()); 99 | } 100 | 101 | 102 | if (activeProfiles.length > 0) { 103 | YamlParserConfig.getProfilingConfig().getApplication().setModuleName( 104 | YamlParserConfig.getProfilingConfig().getApplication().getModuleName() + "-" + 105 | String.join("-", activeProfiles) 106 | ); 107 | } 108 | 109 | 110 | LibraryLoggerConfig.init(); 111 | MonitoringStarting.init(); 112 | GenerateJvmMetrics.init(); 113 | 114 | initializeAgent = true; 115 | YamlParserConfig.setWork(true); 116 | 117 | } catch (Exception e) { 118 | if (LoggerStatusContent.isErrorsOrDebug()) { 119 | initializeAgent = true; 120 | YamlParserConfig.setWork(false); 121 | System.out.println("ByteBuddyAgentInitializer initialize error " + e.getMessage()); 122 | } 123 | } 124 | } 125 | 126 | private boolean isTestEnvironment() { 127 | try { 128 | if ("test".equalsIgnoreCase(System.getProperty("env")) || 129 | "test".equalsIgnoreCase(System.getenv("ENV")) 130 | ) return true; 131 | Class.forName("org.junit.jupiter.api.Test"); 132 | return true; 133 | } catch (ClassNotFoundException e) { 134 | return false; 135 | } 136 | } 137 | } -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/byte_buddy_agent/ByteBuddyAgentKafkaInterceptor.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.byte_buddy_agent; 2 | 3 | import io.bitdive.parent.parserConfig.YamlParserConfig; 4 | import io.bitdive.parent.trasirovka.agent.utils.KafkaAgentStorage; 5 | import io.bitdive.parent.trasirovka.agent.utils.LoggerStatusContent; 6 | import net.bytebuddy.agent.builder.AgentBuilder; 7 | import net.bytebuddy.agent.builder.ResettableClassFileTransformer; 8 | import net.bytebuddy.implementation.MethodDelegation; 9 | import net.bytebuddy.implementation.bind.annotation.AllArguments; 10 | import net.bytebuddy.implementation.bind.annotation.Origin; 11 | import net.bytebuddy.implementation.bind.annotation.RuntimeType; 12 | import net.bytebuddy.implementation.bind.annotation.SuperCall; 13 | import net.bytebuddy.matcher.ElementMatchers; 14 | 15 | import java.lang.instrument.Instrumentation; 16 | import java.lang.reflect.Method; 17 | import java.util.Map; 18 | import java.util.concurrent.Callable; 19 | import java.util.concurrent.ConcurrentHashMap; 20 | 21 | import static io.bitdive.parent.message_producer.MessageService.sendMessageCriticalKafkaError; 22 | 23 | public class ByteBuddyAgentKafkaInterceptor { 24 | 25 | private static final Map NC_BOOTSTRAP_MAP = new ConcurrentHashMap<>(); 26 | 27 | public static ResettableClassFileTransformer init(Instrumentation instrumentation) { 28 | return new AgentBuilder.Default() 29 | .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) 30 | .type(ElementMatchers.named("org.apache.kafka.clients.NetworkClient")) 31 | .transform((builder, typeDescription, classLoader, module, protectionDomain) -> 32 | builder 33 | .method(ElementMatchers.named("processDisconnection")) 34 | .intercept(MethodDelegation.to(ProcessDisconnectionInterceptor.class)) 35 | ) 36 | .installOn(instrumentation); 37 | } 38 | 39 | public static class ProcessDisconnectionInterceptor { 40 | 41 | @RuntimeType 42 | public static Object intercept(@Origin Method method, 43 | @SuperCall Callable zuper, 44 | @AllArguments Object[] args) throws Exception { 45 | 46 | if (LoggerStatusContent.getEnabledProfile()) return zuper.call(); 47 | 48 | Object result = null; 49 | try { 50 | result = zuper.call(); 51 | } catch (Throwable t) { 52 | if (LoggerStatusContent.isErrorsOrDebug()) 53 | System.err.println("ByteBuddyAgentKafkaInterceptor ERROR (calling original method): " + t.getMessage()); 54 | } 55 | 56 | try { 57 | if (args != null && args.length >= 4) { 58 | String nodeId = (args[1] instanceof String) ? (String) args[1] : null; 59 | Object disconnectState = args[3]; 60 | 61 | if (disconnectState != null) { 62 | handleDisconnectState(nodeId, disconnectState); 63 | } 64 | } 65 | } catch (Throwable t) { 66 | if (LoggerStatusContent.isErrorsOrDebug()) 67 | System.err.println("ByteBuddyAgentKafkaInterceptor ERROR (custom logic): " + t.getMessage()); 68 | } 69 | 70 | return result; 71 | } 72 | 73 | 74 | private static void handleDisconnectState(String nodeId, Object disconnectState) { 75 | try { 76 | Method getStateMethod = disconnectState.getClass().getMethod("state"); 77 | Object stateEnum = getStateMethod.invoke(disconnectState); // enum: AUTHENTICATION_FAILED, AUTHENTICATE, NOT_CONNECTED, ... 78 | String stateName = (stateEnum != null) ? stateEnum.toString() : ""; 79 | String remoteAddrStr = KafkaAgentStorage.getBootstrap(); 80 | Method getExceptionMethod = disconnectState.getClass().getMethod("exception"); 81 | Object exceptionObj = getExceptionMethod.invoke(disconnectState); 82 | 83 | String exceptionMsg = (exceptionObj instanceof Throwable) 84 | ? ((Throwable) exceptionObj).getMessage() 85 | : null; 86 | 87 | switch (stateName) { 88 | case "AUTHENTICATION_FAILED": 89 | sendMessageCriticalKafkaError(remoteAddrStr, 90 | String.format("Connection to node %s (%s) failed authentication due to: %s", 91 | nodeId, remoteAddrStr, (exceptionMsg != null ? exceptionMsg : "unknown error")) 92 | ); 93 | break; 94 | case "AUTHENTICATE": 95 | sendMessageCriticalKafkaError(remoteAddrStr, 96 | String.format("Connection to node %s (%s) terminated during authentication. Possible reasons: " + 97 | "(1) Authentication failed due to invalid credentials with brokers older than 1.0.0, " + 98 | "(2) Firewall blocking Kafka TLS traffic, (3) Transient network issue.", 99 | nodeId, remoteAddrStr) 100 | ); 101 | break; 102 | case "NOT_CONNECTED": 103 | sendMessageCriticalKafkaError(remoteAddrStr, 104 | String.format("Connection to node %s (%s) could not be established. Node may not be available.", 105 | nodeId, remoteAddrStr) 106 | ); 107 | break; 108 | default: 109 | break; 110 | } 111 | } catch (NoSuchMethodException e) { 112 | if (LoggerStatusContent.isErrorsOrDebug()) 113 | System.err.println("ByteBuddyAgentKafkaInterceptor ERROR: No such method on disconnectState: " + e.getMessage()); 114 | } catch (Exception e) { 115 | if (LoggerStatusContent.isErrorsOrDebug()) 116 | System.err.println("ByteBuddyAgentKafkaInterceptor ERROR while handling disconnectState: " + e.getMessage()); 117 | } 118 | } 119 | 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/trasirovka/agent/utils/RestUtils.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.trasirovka.agent.utils; 2 | 3 | import java.io.File; 4 | import java.lang.reflect.Method; 5 | import java.nio.charset.Charset; 6 | import java.util.List; 7 | import java.util.Locale; 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | 12 | public class RestUtils { 13 | 14 | 15 | public static String normalizeResponseBodyBytes(byte[] responseBodyBytes, Object responseHeaders, Charset responseCharset) { 16 | if (responseBodyBytes == null || responseBodyBytes.length == 0) { 17 | return ""; 18 | } 19 | // Если по заголовкам определяем, что это файл 20 | if (isFileResponse(responseHeaders)) { 21 | return "[file]"; 22 | } 23 | // Если контент определяется как бинарный, возвращаем заглушку 24 | else if (isBinaryContent(responseHeaders)) { 25 | return "[byte array]"; 26 | } 27 | // Иначе преобразуем массив байт в строку с использованием заданного charset 28 | return new String(responseBodyBytes, responseCharset); 29 | } 30 | 31 | private static boolean isFileResponse(Object headers) { 32 | if (headers == null) return false; 33 | 34 | try { 35 | if (headers instanceof Map) { 36 | Map map = (Map) headers; 37 | 38 | for (Object keyObj : map.keySet()) { 39 | String headerName = keyObj.toString(); 40 | if ("content-disposition".equalsIgnoreCase(headerName)) { 41 | Object value = map.get(headerName); 42 | String headerValue = null; 43 | 44 | if (value instanceof List) { 45 | List list = (List) value; 46 | if (!list.isEmpty()) { 47 | headerValue = String.valueOf(list.get(0)); 48 | } 49 | } else if (value != null) { 50 | headerValue = value.toString(); 51 | } 52 | 53 | if (headerValue != null && headerValue.toLowerCase().contains("attachment")) { 54 | return true; 55 | } 56 | } 57 | } 58 | } else { 59 | // Если не Map, пытаемся использовать reflection (например, для Spring HttpHeaders) 60 | Method keySetMethod = headers.getClass().getMethod("keySet"); 61 | Method getFirstMethod = headers.getClass().getMethod("getFirst", String.class); 62 | 63 | @SuppressWarnings("unchecked") 64 | Set headerNames = (Set) keySetMethod.invoke(headers); 65 | 66 | for (String headerName : headerNames) { 67 | if ("content-disposition".equalsIgnoreCase(headerName)) { 68 | Object headerValue = getFirstMethod.invoke(headers, headerName); 69 | if (headerValue != null && headerValue.toString().toLowerCase().contains("attachment")) { 70 | return true; 71 | } 72 | } 73 | } 74 | } 75 | } catch (Exception e) { 76 | // Лог при необходимости 77 | // e.printStackTrace(); 78 | } 79 | 80 | return false; 81 | } 82 | 83 | private static boolean isBinaryContent(Object headers) { 84 | if (headers == null) return false; 85 | 86 | try { 87 | // Пробуем как Map (например, UnmodifiableMap>) 88 | if (headers instanceof Map) { 89 | Map map = (Map) headers; 90 | 91 | for (Object keyObj : map.keySet()) { 92 | String headerName = keyObj.toString(); 93 | if ("content-type".equalsIgnoreCase(headerName)) { 94 | Object value = map.get(headerName); 95 | String contentType = null; 96 | 97 | if (value instanceof List) { 98 | List list = (List) value; 99 | if (!list.isEmpty()) { 100 | contentType = String.valueOf(list.get(0)); 101 | } 102 | } else if (value != null) { 103 | contentType = value.toString(); 104 | } 105 | 106 | if (contentType != null) { 107 | String type = contentType.toLowerCase(); 108 | if (!type.startsWith("text") && !type.contains("json") && !type.contains("xml")) { 109 | return true; 110 | } 111 | } 112 | } 113 | } 114 | } else { 115 | // Пробуем вызвать метод getContentType() через reflection 116 | Method getContentTypeMethod = headers.getClass().getMethod("getContentType"); 117 | getContentTypeMethod.setAccessible(true); 118 | Object mediaType = getContentTypeMethod.invoke(headers); 119 | if (mediaType != null) { 120 | String type = mediaType.toString().toLowerCase(); 121 | if (!type.startsWith("text") && !type.contains("json") && !type.contains("xml")) { 122 | return true; 123 | } 124 | } 125 | } 126 | } catch (Exception e) { 127 | // Если ошибка — считаем, что контент бинарный 128 | return true; 129 | } 130 | 131 | return false; 132 | } 133 | 134 | 135 | public static String normalizeRequestBody(Object bodyObj) { 136 | if (bodyObj == null) return ""; 137 | // Если это массив байт 138 | if (bodyObj.getClass().isArray() && bodyObj.getClass().getComponentType() == byte.class) { 139 | return "[byte array]"; 140 | } 141 | // Если передаётся файл, MultipartFile или Resource (проверка по имени класса) 142 | if (bodyObj instanceof File 143 | || bodyObj.getClass().getName().equals("org.springframework.web.multipart.MultipartFile") 144 | || bodyObj.getClass().getName().equals("org.springframework.core.io.Resource")) { 145 | return "[file]"; 146 | } 147 | return ReflectionUtils.objectToString(bodyObj); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/main/java/io/bitdive/parent/message_producer/LibraryLoggerConfig.java: -------------------------------------------------------------------------------- 1 | package io.bitdive.parent.message_producer; 2 | 3 | import io.bitdive.parent.parserConfig.ProfilingConfig; 4 | import io.bitdive.parent.parserConfig.YamlParserConfig; 5 | import org.apache.logging.log4j.Level; 6 | import org.apache.logging.log4j.Logger; 7 | import org.apache.logging.log4j.core.LoggerContext; 8 | import org.apache.logging.log4j.core.config.Configuration; 9 | import org.apache.logging.log4j.core.config.builder.api.*; 10 | import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration; 11 | 12 | import java.io.File; 13 | import java.util.Optional; 14 | 15 | 16 | public class LibraryLoggerConfig { 17 | 18 | private static LoggerContext loggerContext; 19 | 20 | 21 | public static void init() { 22 | if (loggerContext != null) { 23 | return; 24 | } 25 | 26 | ConfigurationBuilder builder = ConfigurationBuilderFactory.newConfigurationBuilder(); 27 | 28 | builder.setStatusLevel(Level.WARN); 29 | 30 | AppenderComponentBuilder rollingFileAppender = 31 | builder.newAppender("MonitoringCustomConfig", "RollingRandomAccessFile") 32 | .addAttribute("fileName", YamlParserConfig.getProfilingConfig().getMonitoring().getDataFile().getPath() + File.separator + "monitoringFile.data") 33 | .addAttribute("filePattern", 34 | YamlParserConfig.getProfilingConfig().getMonitoring() 35 | .getDataFile().getPath() 36 | + File.separator + "toSend" + File.separator 37 | + "data-%d{yyyy-MM-dd-HH-mm-ss}-%i_" 38 | + YamlParserConfig.getProfilingConfig().getApplication() 39 | .getServiceName() 40 | + ".data.gz"); 41 | 42 | 43 | LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout").addAttribute("pattern", "%m"); 44 | rollingFileAppender.add(layoutBuilder); 45 | 46 | ComponentBuilder policies = builder.newComponent("Policies") 47 | 48 | .addComponent(builder.newComponent("CronTriggeringPolicy") 49 | .addAttribute("schedule", 50 | "*/" + YamlParserConfig.getProfilingConfig() 51 | .getMonitoring() 52 | .getDataFile() 53 | .getTimerConvertForSend() 54 | + " * * * * ?")) 55 | .addComponent(builder.newComponent("SizeBasedTriggeringPolicy") 56 | .addAttribute("size", "100MB")); 57 | rollingFileAppender.addComponent(policies); 58 | 59 | builder.add(rollingFileAppender); 60 | 61 | AppenderComponentBuilder asyncAppender = builder.newAppender("AsyncAppender", "Async") 62 | .addAttribute("bufferSize", 8096) 63 | .addComponent(builder.newAppenderRef("MonitoringCustomConfig")); 64 | builder.add(asyncAppender); 65 | 66 | AppenderComponentBuilder customHttpAppender = builder.newAppender("CustomHttpAppender", "CustomHttpAppender") 67 | .addAttribute("url", YamlParserConfig.getProfilingConfig().getMonitoring().getSendFiles().getServerConsumer().getUrl()) 68 | .addAttribute("proxyHost", Optional.ofNullable(YamlParserConfig.getProfilingConfig().getMonitoring().getSendFiles().getServerConsumer()) 69 | .map(ProfilingConfig.MonitoringConfig.MonitoringSendFilesConfig.ServerConsumerConfig::getProxy) 70 | .map(ProfilingConfig.MonitoringConfig.MonitoringSendFilesConfig.ServerConsumerConfig.ProxyConfig::getHost) 71 | .orElse(null)) 72 | .addAttribute("proxyPort", Optional.ofNullable(YamlParserConfig.getProfilingConfig().getMonitoring().getSendFiles().getServerConsumer()) 73 | .map(ProfilingConfig.MonitoringConfig.MonitoringSendFilesConfig.ServerConsumerConfig::getProxy) 74 | .map(ProfilingConfig.MonitoringConfig.MonitoringSendFilesConfig.ServerConsumerConfig.ProxyConfig::getPort) 75 | .map(Object::toString) 76 | .orElse(null)) 77 | .addAttribute("proxyUserName", Optional.ofNullable(YamlParserConfig.getProfilingConfig().getMonitoring().getSendFiles().getServerConsumer()) 78 | .map(ProfilingConfig.MonitoringConfig.MonitoringSendFilesConfig.ServerConsumerConfig::getProxy) 79 | .map(ProfilingConfig.MonitoringConfig.MonitoringSendFilesConfig.ServerConsumerConfig.ProxyConfig::getUsername) 80 | .orElse(null)) 81 | .addAttribute("proxyPassword", Optional.ofNullable(YamlParserConfig.getProfilingConfig().getMonitoring().getSendFiles().getServerConsumer()) 82 | .map(ProfilingConfig.MonitoringConfig.MonitoringSendFilesConfig.ServerConsumerConfig::getProxy) 83 | .map(ProfilingConfig.MonitoringConfig.MonitoringSendFilesConfig.ServerConsumerConfig.ProxyConfig::getPassword) 84 | .orElse(null)) 85 | .addAttribute("filePath", YamlParserConfig.getProfilingConfig().getMonitoring().getDataFile().getPath() + File.separator + "toSend") 86 | .addAttribute("fileStorageTime", YamlParserConfig.getProfilingConfig().getMonitoring().getDataFile().getFileStorageTime()); 87 | 88 | builder.add(customHttpAppender); 89 | 90 | RootLoggerComponentBuilder rootLogger = builder.newRootLogger(Level.INFO) 91 | .add(builder.newAppenderRef("AsyncAppender")) 92 | .add(builder.newAppenderRef("CustomHttpAppender")) 93 | .addAttribute("includeLocation", "false"); 94 | 95 | builder.add(rootLogger); 96 | 97 | 98 | Configuration configuration = builder.build(); 99 | 100 | LoggerContext context = new LoggerContext("IsolatedContext"); 101 | context.start(configuration); 102 | 103 | loggerContext = context; 104 | } 105 | 106 | 107 | public static Logger getLogger(Class clazz) { 108 | return loggerContext.getLogger(clazz.getName()); 109 | } 110 | 111 | /** 112 | * Правильная остановка логгер контекста с остановкой всех аппендеров 113 | */ 114 | public static void stopLoggerContext() { 115 | if (loggerContext != null) { 116 | // Явно останавливаем все аппендеры перед остановкой контекста 117 | loggerContext.getConfiguration().getAppenders().values().forEach(appender -> { 118 | if (appender instanceof CustomHttpAppender) { 119 | appender.stop(); 120 | } 121 | }); 122 | loggerContext.stop(); 123 | } 124 | } 125 | } 126 | --------------------------------------------------------------------------------