From 531cd4edc117e66072e839452a892cf4fefebfc4 Mon Sep 17 00:00:00 2001 From: shining-stars-lk <1031900093@qq.com> Date: Fri, 21 Jul 2023 17:52:52 +0800 Subject: [PATCH 01/11] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AD=97=E8=8A=82?= =?UTF-8?q?=E7=A0=81=E5=A2=9E=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 + .../example/ArithmeticApplicationTests.java | 13 - common/pom.xml | 55 +++- cook-async-agent/config/agent.config | 274 ++++++++++++++++ .../cook-async-agent-bootstrap/pom.xml | 141 +++++++++ .../cook-async-agent-core/pom.xml | 175 ++++++++++ .../pom.xml | 29 ++ .../src/main/resources/cook-plugin.def | 17 + .../cook-async-agent-plugin/pom.xml | 130 ++++++++ cook-async-agent/dist-material/LICENSE | 232 ++++++++++++++ cook-async-agent/dist-material/NOTICE | 299 ++++++++++++++++++ ...agent-threadpool-plugin-0.0.1-SNAPSHOT.jar | Bin 0 -> 8285 bytes cook-async-agent/pom.xml | 272 ++++++++++++++++ .../example/DistributeEsApplicationTests.java | 13 - id-generator/pom.xml | 5 + .../example/IdGeneratorApplicationTests.java | 13 - pom.xml | 67 +--- .../DistributeCacheApplicationTests.java | 13 - .../example/controller/TestController.java | 30 ++ .../com/example/service/AccountService.java | 7 +- .../main/resources/mapper/AccountMapper.xml | 7 - tool/pom.xml | 4 + 22 files changed, 1672 insertions(+), 128 deletions(-) delete mode 100644 arithmetic/src/test/java/com/example/ArithmeticApplicationTests.java create mode 100644 cook-async-agent/config/agent.config create mode 100644 cook-async-agent/cook-async-agent-bootstrap/pom.xml create mode 100644 cook-async-agent/cook-async-agent-core/pom.xml create mode 100644 cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/pom.xml create mode 100644 cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/resources/cook-plugin.def create mode 100644 cook-async-agent/cook-async-agent-plugin/pom.xml create mode 100644 cook-async-agent/dist-material/LICENSE create mode 100644 cook-async-agent/dist-material/NOTICE create mode 100644 cook-async-agent/hippo4j-agent/plugins/cook-async-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar create mode 100644 cook-async-agent/pom.xml delete mode 100644 distribute-es/src/test/java/com/example/DistributeEsApplicationTests.java delete mode 100644 id-generator/src/test/java/com/example/IdGeneratorApplicationTests.java delete mode 100644 redis-tool/src/test/java/com/example/DistributeCacheApplicationTests.java create mode 100644 server/server-case/src/main/java/com/example/controller/TestController.java delete mode 100644 server/server-case/src/main/resources/mapper/AccountMapper.xml diff --git a/.gitignore b/.gitignore index 9f4d3c06..3f895d09 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,10 @@ target/ !**/src/test/**/target/ logs/ +### Agent ### +agent/ +**/dependency-reduced-pom.xml + ### STS ### .apt_generated .classpath diff --git a/arithmetic/src/test/java/com/example/ArithmeticApplicationTests.java b/arithmetic/src/test/java/com/example/ArithmeticApplicationTests.java deleted file mode 100644 index 4cb79dc5..00000000 --- a/arithmetic/src/test/java/com/example/ArithmeticApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.example; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class ArithmeticApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/common/pom.xml b/common/pom.xml index 24a808a6..5b986e79 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -11,7 +11,6 @@ common - common 公共 @@ -46,6 +45,60 @@ hutool-all 5.8.16 + + + com.alibaba + fastjson + 1.2.83 + + + org.springframework.boot + spring-boot-starter-log4j2 + + + org.slf4j + slf4j-log4j12 + + + org.apache.logging.log4j + log4j-core + + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.apache.logging.log4j + log4j-web + + + + + org.apache.logging.log4j + log4j-core + 2.17.0 + + + + org.apache.logging.log4j + log4j-api + 2.17.0 + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.17.0 + + + org.apache.logging.log4j + log4j-web + 2.17.0 + diff --git a/cook-async-agent/config/agent.config b/cook-async-agent/config/agent.config new file mode 100644 index 00000000..26de71cc --- /dev/null +++ b/cook-async-agent/config/agent.config @@ -0,0 +1,274 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# The service name in UI +# ${service name} = [${group name}::]${logic name} +# The group name is optional only. +agent.service_name=${SW_AGENT_NAME:Your_ApplicationName} + +# The agent namespace +agent.namespace=${SW_AGENT_NAMESPACE:} + +# The agent cluster +agent.cluster=${SW_AGENT_CLUSTER:} + +# The number of sampled traces per 3 seconds +# Negative or zero means off, by default +agent.sample_n_per_3_secs=${SW_AGENT_SAMPLE:-1} + +# Authentication active is based on backend setting, see application.yml for more details. +agent.authentication=${SW_AGENT_AUTHENTICATION:} + +# The max number of TraceSegmentRef in a single span to keep memory cost estimatable. +agent.trace_segment_ref_limit_per_span=${SW_TRACE_SEGMENT_LIMIT:500} + +# The max amount of spans in a single segment. +# Through this config item, SkyWalking keep your application memory cost estimated. +agent.span_limit_per_segment=${SW_AGENT_SPAN_LIMIT:300} + +# If the operation name of the first span is included in this set, this segment should be ignored. Multiple values should be separated by `,`. +agent.ignore_suffix=${SW_AGENT_IGNORE_SUFFIX:.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg} + +# If true, SkyWalking agent will save all instrumented classes files in `/debugging` folder. +# SkyWalking team may ask for these files in order to resolve compatible problem. +agent.is_open_debugging_class=${SW_AGENT_OPEN_DEBUG:false} + +# If true, SkyWalking agent will cache all instrumented classes files to memory or disk files (decided by class cache mode), +# allow other javaagent to enhance those classes that enhanced by SkyWalking agent. +agent.is_cache_enhanced_class=${SW_AGENT_CACHE_CLASS:false} + +# The instrumented classes cache mode: MEMORY or FILE +# MEMORY: cache class bytes to memory, if instrumented classes is too many or too large, it may take up more memory +# FILE: cache class bytes in `/class-cache` folder, automatically clean up cached class files when the application exits +agent.class_cache_mode=${SW_AGENT_CLASS_CACHE_MODE:MEMORY} + +# Instance name is the identity of an instance, should be unique in the service. If empty, SkyWalking agent will +# generate an 32-bit uuid. BY Default, SkyWalking uses UUID@hostname as the instance name. Max length is 50(UTF-8 char) +agent.instance_name=${SW_AGENT_INSTANCE_NAME:} + +# service instance properties in json format. e.g. agent.instance_properties_json = {"org": "apache-skywalking"} +agent.instance_properties_json=${SW_INSTANCE_PROPERTIES_JSON:} + +# How depth the agent goes, when log all cause exceptions. +agent.cause_exception_depth=${SW_AGENT_CAUSE_EXCEPTION_DEPTH:5} + +# Force reconnection period of grpc, based on grpc_channel_check_interval. +agent.force_reconnection_period=${SW_AGENT_FORCE_RECONNECTION_PERIOD:1} + +# The operationName max length +# Notice, in the current practice, we don't recommend the length over 190. +agent.operation_name_threshold=${SW_AGENT_OPERATION_NAME_THRESHOLD:150} + +# Keep tracing even the backend is not available if this value is true. +agent.keep_tracing=${SW_AGENT_KEEP_TRACING:false} + +# The agent use gRPC plain text in default. +# If true, SkyWalking agent uses TLS even no CA file detected. +agent.force_tls=${SW_AGENT_FORCE_TLS:false} + +# gRPC SSL trusted ca file. +agent.ssl_trusted_ca_path=${SW_AGENT_SSL_TRUSTED_CA_PATH:/ca/ca.crt} + +# enable mTLS when ssl_key_path and ssl_cert_chain_path exist. +agent.ssl_key_path=${SW_AGENT_SSL_KEY_PATH:} + +agent.ssl_cert_chain_path=${SW_AGENT_SSL_CERT_CHAIN_PATH:} + +# Limit the length of the ipv4 list size. +osinfo.ipv4_list_size=${SW_AGENT_OSINFO_IPV4_LIST_SIZE:10} + +# grpc channel status check interval. +collector.grpc_channel_check_interval=${SW_AGENT_COLLECTOR_GRPC_CHANNEL_CHECK_INTERVAL:30} +# Agent heartbeat report period. Unit, second. +collector.heartbeat_period=${SW_AGENT_COLLECTOR_HEARTBEAT_PERIOD:30} +# The agent sends the instance properties to the backend every +# collector.heartbeat_period * collector.properties_report_period_factor seconds +collector.properties_report_period_factor=${SW_AGENT_COLLECTOR_PROPERTIES_REPORT_PERIOD_FACTOR:10} +# Backend service addresses. +collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:127.0.0.1:11800} +# How long grpc client will timeout in sending data to upstream. Unit is second. +collector.grpc_upstream_timeout=${SW_AGENT_COLLECTOR_GRPC_UPSTREAM_TIMEOUT:30} +# Sniffer get profile task list interval. +collector.get_profile_task_interval=${SW_AGENT_COLLECTOR_GET_PROFILE_TASK_INTERVAL:20} +# Sniffer get agent dynamic config interval. +collector.get_agent_dynamic_config_interval=${SW_AGENT_COLLECTOR_GET_AGENT_DYNAMIC_CONFIG_INTERVAL:20} +# If true, skywalking agent will enable periodically resolving DNS to update receiver service addresses. +collector.is_resolve_dns_periodically=${SW_AGENT_COLLECTOR_IS_RESOLVE_DNS_PERIODICALLY:false} + +# Logging level +logging.level=${SW_LOGGING_LEVEL:INFO} +# Logging file_name +logging.file_name=${SW_LOGGING_FILE_NAME:cook-async-api.log} +# Log output. Default is FILE. Use CONSOLE means output to stdout. +logging.output=${SW_LOGGING_OUTPUT:FILE} +# Log files directory. Default is blank string, meaning use "{thecook-asyncAgentJarDir}/logs " to output logs. +# {thecook-asyncAgentJarDir} is the directory where the cook-async agent jar file is located +logging.dir=${SW_LOGGING_DIR:} +# Logger resolver: PATTERN or JSON. The default is PATTERN, which uses logging.pattern to print traditional text logs. +# JSON resolver prints logs in JSON format. +logging.resolver=${SW_LOGGING_RESOLVER:PATTERN} +# Logging format. There are all conversion specifiers: +# * %level means log level. +# * %timestamp means now of time with format yyyy-MM-dd HH:mm:ss:SSS. +# * %thread means name of current thread. +# * %msg means some message which user logged. +# * %class means SimpleName of TargetClass. +# * %throwable means a throwable which user called. +# * %agent_name means agent.service_name. Only apply to the PatternLogger. +logging.pattern=${SW_LOGGING_PATTERN:%level %timestamp %thread %class : %msg %throwable} +# Logging max_file_size, default: 300 * 1024 * 1024 = 314572800 +logging.max_file_size=${SW_LOGGING_MAX_FILE_SIZE:314572800} +# The max history log files. When rollover happened, if log files exceed this number, +# then the oldest file will be delete. Negative or zero means off, by default. +logging.max_history_files=${SW_LOGGING_MAX_HISTORY_FILES:-1} + +# Listed exceptions would not be treated as an error. Because in some codes, the exception is being used as a way of controlling business flow. +# Besides, the annotation named IgnoredException in the trace toolkit is another way to configure ignored exceptions. +statuscheck.ignored_exceptions=${SW_STATUSCHECK_IGNORED_EXCEPTIONS:} +# The max recursive depth when checking the exception traced by the agent. Typically, we don't recommend setting this more than 10, which could cause a performance issue. Negative value and 0 would be ignored, which means all exceptions would make the span tagged in error status. +statuscheck.max_recursive_depth=${SW_STATUSCHECK_MAX_RECURSIVE_DEPTH:1} + +# Max element count in the correlation context +correlation.element_max_number=${SW_CORRELATION_ELEMENT_MAX_NUMBER:3} + +# Max value length of each element. +correlation.value_max_length=${SW_CORRELATION_VALUE_MAX_LENGTH:128} +# Tag the span by the key/value in the correlation context, when the keys listed here exist. +correlation.auto_tag_keys=${SW_CORRELATION_AUTO_TAG_KEYS:} +# The buffer size of collected JVM info. +jvm.buffer_size=${SW_JVM_BUFFER_SIZE:600} +# The buffer channel size. +buffer.channel_size=${SW_BUFFER_CHANNEL_SIZE:5} +# The buffer size. +buffer.buffer_size=${SW_BUFFER_BUFFER_SIZE:300} +# If true, skywalking agent will enable profile when user create a new profile task. Otherwise disable profile. +profile.active=${SW_AGENT_PROFILE_ACTIVE:true} +# Parallel monitor segment count +profile.max_parallel=${SW_AGENT_PROFILE_MAX_PARALLEL:5} +# Max monitor segment time(minutes), if current segment monitor time out of limit, then stop it. +profile.duration=${SW_AGENT_PROFILE_DURATION:10} +# Max dump thread stack depth +profile.dump_max_stack_depth=${SW_AGENT_PROFILE_DUMP_MAX_STACK_DEPTH:500} +# Snapshot transport to backend buffer size +profile.snapshot_transport_buffer_size=${SW_AGENT_PROFILE_SNAPSHOT_TRANSPORT_BUFFER_SIZE:4500} +# If true, the agent collects and reports metrics to the backend. +meter.active=${SW_METER_ACTIVE:true} +# Report meters interval. The unit is second +meter.report_interval=${SW_METER_REPORT_INTERVAL:20} +# Max size of the meter pool +meter.max_meter_size=${SW_METER_MAX_METER_SIZE:500} +# The max size of message to send to server.Default is 10 MB +log.max_message_size=${SW_GRPC_LOG_MAX_MESSAGE_SIZE:10485760} + +# Mount the specific folders of the plugins. Plugins in mounted folders would work. +plugin.mount=${SW_MOUNT_FOLDERS:plugins,activations} +# Peer maximum description limit. +plugin.peer_max_length=${SW_PLUGIN_PEER_MAX_LENGTH:200} +# Exclude some plugins define in plugins dir.Plugin names is defined in [Agent plugin list](Plugin-list.md) +plugin.exclude_plugins=${SW_EXCLUDE_PLUGINS:} +# If true, trace all the parameters in MongoDB access, default is false. Only trace the operation, not include parameters. +plugin.mongodb.trace_param=${SW_PLUGIN_MONGODB_TRACE_PARAM:false} +# If set to positive number, the `WriteRequest.params` would be truncated to this length, otherwise it would be completely saved, which may cause performance problem. +plugin.mongodb.filter_length_limit=${SW_PLUGIN_MONGODB_FILTER_LENGTH_LIMIT:256} +# If true, trace all the DSL(Domain Specific Language) in ElasticSearch access, default is false. +plugin.elasticsearch.trace_dsl=${SW_PLUGIN_ELASTICSEARCH_TRACE_DSL:false} +# If true, the fully qualified method name will be used as the endpoint name instead of the request URL, default is false. +plugin.springmvc.use_qualified_name_as_endpoint_name=${SW_PLUGIN_SPRINGMVC_USE_QUALIFIED_NAME_AS_ENDPOINT_NAME:false} +# If true, the fully qualified method name will be used as the operation name instead of the given operation name, default is false. +plugin.toolit.use_qualified_name_as_operation_name=${SW_PLUGIN_TOOLIT_USE_QUALIFIED_NAME_AS_OPERATION_NAME:false} +# If set to true, the parameters of the sql (typically `java.sql.PreparedStatement`) would be collected. +plugin.jdbc.trace_sql_parameters=${SW_JDBC_TRACE_SQL_PARAMETERS:false} +# If set to positive number, the `db.sql.parameters` would be truncated to this length, otherwise it would be completely saved, which may cause performance problem. +plugin.jdbc.sql_parameters_max_length=${SW_PLUGIN_JDBC_SQL_PARAMETERS_MAX_LENGTH:512} +# If set to positive number, the `db.statement` would be truncated to this length, otherwise it would be completely saved, which may cause performance problem. +plugin.jdbc.sql_body_max_length=${SW_PLUGIN_JDBC_SQL_BODY_MAX_LENGTH:2048} +# If true, trace all the query parameters(include deleteByIds and deleteByQuery) in Solr query request, default is false. +plugin.solrj.trace_statement=${SW_PLUGIN_SOLRJ_TRACE_STATEMENT:false} +# If true, trace all the operation parameters in Solr request, default is false. +plugin.solrj.trace_ops_params=${SW_PLUGIN_SOLRJ_TRACE_OPS_PARAMS:false} +# If true, trace all middleware/business handlers that are part of the Light4J handler chain for a request. +plugin.light4j.trace_handler_chain=${SW_PLUGIN_LIGHT4J_TRACE_HANDLER_CHAIN:false} +# If true, the transaction definition name will be simplified. +plugin.springtransaction.simplify_transaction_definition_name=${SW_PLUGIN_SPRINGTRANSACTION_SIMPLIFY_TRANSACTION_DEFINITION_NAME:false} +# Threading classes (`java.lang.Runnable` and `java.util.concurrent.Callable`) and their subclasses, including anonymous inner classes whose name match any one of the `THREADING_CLASS_PREFIXES` (splitted by `,`) will be instrumented, make sure to only specify as narrow prefixes as what you're expecting to instrument, (`java.` and `javax.` will be ignored due to safety issues) +plugin.jdkthreading.threading_class_prefixes=${SW_PLUGIN_JDKTHREADING_THREADING_CLASS_PREFIXES:} +# This config item controls that whether the Tomcat plugin should collect the parameters of the request. Also, activate implicitly in the profiled trace. +plugin.tomcat.collect_http_params=${SW_PLUGIN_TOMCAT_COLLECT_HTTP_PARAMS:false} +# This config item controls that whether the SpringMVC plugin should collect the parameters of the request, when your Spring application is based on Tomcat, consider only setting either `plugin.tomcat.collect_http_params` or `plugin.springmvc.collect_http_params`. Also, activate implicitly in the profiled trace. +plugin.springmvc.collect_http_params=${SW_PLUGIN_SPRINGMVC_COLLECT_HTTP_PARAMS:false} +# This config item controls that whether the HttpClient plugin should collect the parameters of the request +plugin.httpclient.collect_http_params=${SW_PLUGIN_HTTPCLIENT_COLLECT_HTTP_PARAMS:false} +# When `COLLECT_HTTP_PARAMS` is enabled, how many characters to keep and send to the OAP backend, use negative values to keep and send the complete parameters, NB. this config item is added for the sake of performance. +plugin.http.http_params_length_threshold=${SW_PLUGIN_HTTP_HTTP_PARAMS_LENGTH_THRESHOLD:1024} +# When `include_http_headers` declares header names, this threshold controls the length limitation of all header values. use negative values to keep and send the complete headers. Note. this config item is added for the sake of performance. +plugin.http.http_headers_length_threshold=${SW_PLUGIN_HTTP_HTTP_HEADERS_LENGTH_THRESHOLD:2048} +# Set the header names, which should be collected by the plugin. Header name must follow `javax.servlet.http` definition. Multiple names should be split by comma. +plugin.http.include_http_headers=${SW_PLUGIN_HTTP_INCLUDE_HTTP_HEADERS:} +# This config item controls that whether the Feign plugin should collect the http body of the request. +plugin.feign.collect_request_body=${SW_PLUGIN_FEIGN_COLLECT_REQUEST_BODY:false} +# When `COLLECT_REQUEST_BODY` is enabled, how many characters to keep and send to the OAP backend, use negative values to keep and send the complete body. +plugin.feign.filter_length_limit=${SW_PLUGIN_FEIGN_FILTER_LENGTH_LIMIT:1024} +# When `COLLECT_REQUEST_BODY` is enabled and content-type start with SUPPORTED_CONTENT_TYPES_PREFIX, collect the body of the request , multiple paths should be separated by `,` +plugin.feign.supported_content_types_prefix=${SW_PLUGIN_FEIGN_SUPPORTED_CONTENT_TYPES_PREFIX:application/json,text/} +# If true, trace all the influxql(query and write) in InfluxDB access, default is true. +plugin.influxdb.trace_influxql=${SW_PLUGIN_INFLUXDB_TRACE_INFLUXQL:true} +# Apache Dubbo consumer collect `arguments` in RPC call, use `Object#toString` to collect `arguments`. +plugin.dubbo.collect_consumer_arguments=${SW_PLUGIN_DUBBO_COLLECT_CONSUMER_ARGUMENTS:false} +# When `plugin.dubbo.collect_consumer_arguments` is `true`, Arguments of length from the front will to the OAP backend +plugin.dubbo.consumer_arguments_length_threshold=${SW_PLUGIN_DUBBO_CONSUMER_ARGUMENTS_LENGTH_THRESHOLD:256} +# Apache Dubbo provider collect `arguments` in RPC call, use `Object#toString` to collect `arguments`. +plugin.dubbo.collect_provider_arguments=${SW_PLUGIN_DUBBO_COLLECT_PROVIDER_ARGUMENTS:false} +# When `plugin.dubbo.collect_provider_arguments` is `true`, Arguments of length from the front will to the OAP backend +plugin.dubbo.provider_arguments_length_threshold=${SW_PLUGIN_DUBBO_PROVIDER_ARGUMENTS_LENGTH_THRESHOLD:256} +# A list of host/port pairs to use for establishing the initial connection to the Kafka cluster. +plugin.kafka.bootstrap_servers=${SW_KAFKA_BOOTSTRAP_SERVERS:localhost:9092} +# Timeout period of reading topics from the Kafka server, the unit is second. +plugin.kafka.get_topic_timeout=${SW_GET_TOPIC_TIMEOUT:10} +# Kafka producer configuration. Read [producer configure](http://kafka.apache.org/24/documentation.html#producerconfigs) +# to get more details. Check document for more details and examples. +plugin.kafka.producer_config=${sw_plugin_kafka_producer_config:} +# Configure Kafka Producer configuration in JSON format. Notice it will be overridden by plugin.kafka.producer_config[key], if the key duplication. +plugin.kafka.producer_config_json=${SW_PLUGIN_KAFKA_PRODUCER_CONFIG_JSON:} +# Specify which Kafka topic name for Meter System data to report to. +plugin.kafka.topic_meter=${SW_PLUGIN_KAFKA_TOPIC_METER:skywalking-meters} +# Specify which Kafka topic name for JVM metrics data to report to. +plugin.kafka.topic_metrics=${SW_PLUGIN_KAFKA_TOPIC_METRICS:skywalking-metrics} +# Specify which Kafka topic name for traces data to report to. +plugin.kafka.topic_segment=${SW_PLUGIN_KAFKA_TOPIC_SEGMENT:skywalking-segments} +# Specify which Kafka topic name for Thread Profiling snapshot to report to. +plugin.kafka.topic_profiling=${SW_PLUGIN_KAFKA_TOPIC_PROFILINGS:skywalking-profilings} +# Specify which Kafka topic name for the register or heartbeat data of Service Instance to report to. +plugin.kafka.topic_management=${SW_PLUGIN_KAFKA_TOPIC_MANAGEMENT:skywalking-managements} +# Specify which Kafka topic name for the logging data to report to. +plugin.kafka.topic_logging=${SW_PLUGIN_KAFKA_TOPIC_LOGGING:skywalking-logs} +# isolate multi OAP server when using same Kafka cluster (final topic name will append namespace before Kafka topics with `-` ). +plugin.kafka.namespace=${SW_KAFKA_NAMESPACE:} +# Match spring beans with regular expression for the class name. Multiple expressions could be separated by a comma. This only works when `Spring annotation plugin` has been activated. +plugin.springannotation.classname_match_regex=${SW_SPRINGANNOTATION_CLASSNAME_MATCH_REGEX:} +# Whether or not to transmit logged data as formatted or un-formatted. +plugin.toolkit.log.transmit_formatted=${SW_PLUGIN_TOOLKIT_LOG_TRANSMIT_FORMATTED:true} +# If set to true, the parameters of Redis commands would be collected by Lettuce agent. +plugin.lettuce.trace_redis_parameters=${SW_PLUGIN_LETTUCE_TRACE_REDIS_PARAMETERS:false} +# If set to positive number and `plugin.lettuce.trace_redis_parameters` is set to `true`, Redis command parameters would be collected and truncated to this length. +plugin.lettuce.redis_parameter_max_length=${SW_PLUGIN_LETTUCE_REDIS_PARAMETER_MAX_LENGTH:128} +# If set to true, the parameters of the cypher would be collected. +plugin.neo4j.trace_cypher_parameters=${SW_PLUGIN_NEO4J_TRACE_CYPHER_PARAMETERS:false} +# If set to positive number, the `db.cypher.parameters` would be truncated to this length, otherwise it would be completely saved, which may cause performance problem. +plugin.neo4j.cypher_parameters_max_length=${SW_PLUGIN_NEO4J_CYPHER_PARAMETERS_MAX_LENGTH:512} +# If set to positive number, the `db.statement` would be truncated to this length, otherwise it would be completely saved, which may cause performance problem. +plugin.neo4j.cypher_body_max_length=${SW_PLUGIN_NEO4J_CYPHER_BODY_MAX_LENGTH:2048} +# If set to a positive number and activate `trace sampler CPU policy plugin`, the trace would not be collected when agent process CPU usage percent is greater than `plugin.cpupolicy.sample_cpu_usage_percent_limit`. +plugin.cpupolicy.sample_cpu_usage_percent_limit=${SW_SAMPLE_CPU_USAGE_PERCENT_LIMIT:-1} diff --git a/cook-async-agent/cook-async-agent-bootstrap/pom.xml b/cook-async-agent/cook-async-agent-bootstrap/pom.xml new file mode 100644 index 00000000..b5fa8db7 --- /dev/null +++ b/cook-async-agent/cook-async-agent-bootstrap/pom.xml @@ -0,0 +1,141 @@ + + + + + 4.0.0 + + com.example + cook-async-agent + ${revision} + + cook-async-agent-bootstrap + + jar + + + UTF-8 + com.example.agent.bootstrap.CookAsyncAgent + true + true + net.bytebuddy + ${shade.package}.${shade.net.bytebuddy.source} + + + + + com.example + cook-async-agent-core + ${project.version} + + + + + cook-async-agent + + + maven-shade-plugin + + + package + + shade + + + false + true + true + true + + + + ${premain.class} + ${can.redefine.classes} + ${can.retransform.classes} + + + + + + *:gson + io.grpc:* + io.netty:* + io.opencensus:* + com.google.*:* + com.google.guava:guava + org.checkerframework:checker-compat-qual + org.codehaus.mojo:animal-sniffer-annotations + io.perfmark:* + org.slf4j:* + + + + + ${shade.net.bytebuddy.source} + ${shade.net.bytebuddy.target} + + + + + net.bytebuddy:byte-buddy + + META-INF/versions/9/module-info.class + + + + + + + + + maven-antrun-plugin + + + clean + clean + + run + + + + + + + + + package + package + + run + + + + + + + + + + + + + + + + + diff --git a/cook-async-agent/cook-async-agent-core/pom.xml b/cook-async-agent/cook-async-agent-core/pom.xml new file mode 100644 index 00000000..4472c3da --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/pom.xml @@ -0,0 +1,175 @@ + + + + + 4.0.0 + + com.example + cook-async-agent + ${revision} + + cook-async-agent-core + + + UTF-8 + 2.0.7.Final + 1.4.1.Final + com.google + ${shade.package}.${shade.com.google.source} + io.grpc + ${shade.package}.${shade.io.grpc.source} + io.netty + ${shade.package}.${shade.io.netty.source} + io.opencensus + ${shade.package}.${shade.io.opencensus.source} + io.perfmark + ${shade.package}.${shade.io.perfmark.source} + org.slf4j + ${shade.package}.${shade.org.slf4j.source} + 1.18.0 + + + + + net.bytebuddy + byte-buddy + + + com.google.code.gson + gson + + + org.projectlombok + lombok + + + net.bytebuddy + byte-buddy-agent + test + + + com.github.tomakehurst + wiremock + test + + + jackson-annotations + com.fasterxml.jackson.core + + + jackson-core + com.fasterxml.jackson.core + + + jackson-databind + com.fasterxml.jackson.core + + + + + org.openjdk.jmh + jmh-generator-annprocess + test + + + com.google.code.gson + gson + + + + + + + kr.motd.maven + os-maven-plugin + ${os-maven-plugin.version} + + + initialize + + detect + + + + + + maven-shade-plugin + + + package + + shade + + + + + net.bytebuddy:byte-buddy:jar: + com.google.errorprone:error_prone_annotations:jar: + com.google.code.findbugs:jsr305:jar: + com.google.android:annotations:jar: + com.google.api.grpc:proto-google-common-protos:jar: + org.checkerframework:checker-compat-qual:jar: + org.codehaus.mojo:animal-sniffer-annotations:jar: + + + + + ${shade.com.google.source} + ${shade.com.google.target} + + + ${shade.io.grpc.source} + ${shade.io.grpc.target} + + + ${shade.io.netty.source} + ${shade.io.netty.target} + + + ${shade.io.opencensus.source} + ${shade.io.opencensus.target} + + + ${shade.io.perfmark.source} + ${shade.io.perfmark.target} + + + ${shade.org.slf4j.source} + ${shade.org.slf4j.target} + + + + + com.google.protobuf:protobuf-java + + google/protobuf/*.proto + google/protobuf/compiler/*.proto + + + + + + + + + + + + + diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/pom.xml b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/pom.xml new file mode 100644 index 00000000..995edfeb --- /dev/null +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + com.example + cook-async-agent-plugin + ${revision} + + + cook-async-agent-threadpool-plugin + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + org.springframework + spring-webmvc + 5.2.15.RELEASE + provided + + + \ No newline at end of file diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/resources/cook-plugin.def b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/resources/cook-plugin.def new file mode 100644 index 00000000..366bff0d --- /dev/null +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/resources/cook-plugin.def @@ -0,0 +1,17 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +thread-pool-plugin=com.example.agent.plugin.thread.define.ThreadPoolExecutorInstrumentation \ No newline at end of file diff --git a/cook-async-agent/cook-async-agent-plugin/pom.xml b/cook-async-agent/cook-async-agent-plugin/pom.xml new file mode 100644 index 00000000..760356df --- /dev/null +++ b/cook-async-agent/cook-async-agent-plugin/pom.xml @@ -0,0 +1,130 @@ + + + + + 4.0.0 + + com.example + cook-async-agent + ${revision} + + cook-async-agent-plugin + pom + + cook-async-agent-threadpool-plugin + + + + UTF-8 + + net.bytebuddy + ${shade.package}.${shade.net.bytebuddy.source} + + ${project.build.directory}${sdk.plugin.related.dir}/../../../agent + + ${agent.package.dest.dir}/plugins + + 1.0b3 + 1.8.1 + + + + + com.example + cook-async-agent-core + ${project.version} + provided + + + net.bytebuddy + byte-buddy + provided + + + + + + + maven-shade-plugin + + + package + + shade + + + false + true + true + true + + + ${shade.net.bytebuddy.source} + ${shade.net.bytebuddy.target} + + + + + + + + maven-antrun-plugin + + + package + + run + + + + + + + + + + + + + + + + + + + ant-contrib + ant-contrib + ${ant-contrib.version} + + + ant + ant + + + + + org.apache.ant + ant-nodeps + ${ant-nodeps.version} + + + + + + diff --git a/cook-async-agent/dist-material/LICENSE b/cook-async-agent/dist-material/LICENSE new file mode 100644 index 00000000..f84d20b7 --- /dev/null +++ b/cook-async-agent/dist-material/LICENSE @@ -0,0 +1,232 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +======================================================================= +Apache SkyWalking Subcomponents: + +The Apache SkyWalking project contains subcomponents with separate copyright +notices and license terms. Your use of the source code for the these +subcomponents is subject to the terms and conditions of the following +licenses. + +======================================================================== +Apache 2.0 licenses +======================================================================== + +The following components are provided under the Apache License. See project link for details. +The text of each license is the standard Apache 2.0 license. + + raphw (byte-buddy) 1.12.13: http://bytebuddy.net/ , Apache 2.0 + Google: grpc-java 1.44.0: https://github.com/grpc/grpc-java, Apache 2.0 + Google: gson 2.8.9: https://github.com/google/gson , Apache 2.0 + Google: proto-google-common-protos 2.0.1: https://github.com/googleapis/googleapis , Apache 2.0 + Google: jsr305 3.0.2: http://central.maven.org/maven2/com/google/code/findbugs/jsr305/3.0.0/jsr305-3.0.0.pom , Apache 2.0 + netty 4.1.79: https://github.com/netty/netty/blob/4.1/LICENSE.txt, Apache 2.0 + +======================================================================== +BSD licenses +======================================================================== + +The following components are provided under a BSD license. See project link for details. +The text of each license is also included at licenses/LICENSE-[project].txt. + + asm 9.2:https://gitlab.ow2.org , BSD-3-Clause diff --git a/cook-async-agent/dist-material/NOTICE b/cook-async-agent/dist-material/NOTICE new file mode 100644 index 00000000..666f0a69 --- /dev/null +++ b/cook-async-agent/dist-material/NOTICE @@ -0,0 +1,299 @@ +shining-starts-lk +Copyright 2017-2022 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +======================================================================== + +grpc-java NOTICE + +======================================================================== +Copyright 2014, gRPC Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +----------------------------------------------------------------------- + +This product contains a modified portion of 'OkHttp', an open source +HTTP & SPDY client for Android and Java applications, which can be obtained +at: + + * LICENSE: + * okhttp/third_party/okhttp/LICENSE (Apache License 2.0) + * HOMEPAGE: + * https://github.com/square/okhttp + * LOCATION_IN_GRPC: + * okhttp/third_party/okhttp + +This product contains a modified portion of 'Netty', an open source +networking library, which can be obtained at: + + * LICENSE: + * netty/third_party/netty/LICENSE.txt (Apache License 2.0) + * HOMEPAGE: + * https://netty.io + * LOCATION_IN_GRPC: + * netty/third_party/netty + +======================================================================== + +grpc NOTICE + +======================================================================== + +Copyright 2014 gRPC authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +======================================================================== + +netty NOTICE + +======================================================================== + + + The Netty Project + ================= + +Please visit the Netty web site for more information: + + * http://netty.io/ + +Copyright 2014 The Netty Project + +The Netty Project licenses this file to you under the Apache License, +version 2.0 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +License for the specific language governing permissions and limitations +under the License. + +Also, please refer to each LICENSE..txt file, which is located in +the 'license' directory of the distribution file, for the license terms of the +components that this product depends on. + +------------------------------------------------------------------------------- +This product contains the extensions to Java Collections Framework which has +been derived from the works by JSR-166 EG, Doug Lea, and Jason T. Greene: + + * LICENSE: + * license/LICENSE.jsr166y.txt (Public Domain) + * HOMEPAGE: + * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/ + * http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbosscache/experimental/jsr166/ + +This product contains a modified version of Robert Harder's Public Domain +Base64 Encoder and Decoder, which can be obtained at: + + * LICENSE: + * license/LICENSE.base64.txt (Public Domain) + * HOMEPAGE: + * http://iharder.sourceforge.net/current/java/base64/ + +This product contains a modified portion of 'Webbit', an event based +WebSocket and HTTP server, which can be obtained at: + + * LICENSE: + * license/LICENSE.webbit.txt (BSD License) + * HOMEPAGE: + * https://github.com/joewalnes/webbit + +This product contains a modified portion of 'SLF4J', a simple logging +facade for Java, which can be obtained at: + + * LICENSE: + * license/LICENSE.slf4j.txt (MIT License) + * HOMEPAGE: + * http://www.slf4j.org/ + +This product contains a modified portion of 'Apache Harmony', an open source +Java SE, which can be obtained at: + + * NOTICE: + * license/NOTICE.harmony.txt + * LICENSE: + * license/LICENSE.harmony.txt (Apache License 2.0) + * HOMEPAGE: + * http://archive.apache.org/dist/harmony/ + +This product contains a modified portion of 'jbzip2', a Java bzip2 compression +and decompression library written by Matthew J. Francis. It can be obtained at: + + * LICENSE: + * license/LICENSE.jbzip2.txt (MIT License) + * HOMEPAGE: + * https://code.google.com/p/jbzip2/ + +This product contains a modified portion of 'libdivsufsort', a C API library to construct +the suffix array and the Burrows-Wheeler transformed string for any input string of +a constant-size alphabet written by Yuta Mori. It can be obtained at: + + * LICENSE: + * license/LICENSE.libdivsufsort.txt (MIT License) + * HOMEPAGE: + * https://github.com/y-256/libdivsufsort + +This product contains a modified portion of Nitsan Wakart's 'JCTools', Java Concurrency Tools for the JVM, + which can be obtained at: + + * LICENSE: + * license/LICENSE.jctools.txt (ASL2 License) + * HOMEPAGE: + * https://github.com/JCTools/JCTools + +This product optionally depends on 'JZlib', a re-implementation of zlib in +pure Java, which can be obtained at: + + * LICENSE: + * license/LICENSE.jzlib.txt (BSD style License) + * HOMEPAGE: + * http://www.jcraft.com/jzlib/ + +This product optionally depends on 'Compress-LZF', a Java library for encoding and +decoding data in LZF format, written by Tatu Saloranta. It can be obtained at: + + * LICENSE: + * license/LICENSE.compress-lzf.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/ning/compress + +This product optionally depends on 'lz4', a LZ4 Java compression +and decompression library written by Adrien Grand. It can be obtained at: + + * LICENSE: + * license/LICENSE.lz4.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/jpountz/lz4-java + +This product optionally depends on 'lzma-java', a LZMA Java compression +and decompression library, which can be obtained at: + + * LICENSE: + * license/LICENSE.lzma-java.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/jponge/lzma-java + +This product contains a modified portion of 'jfastlz', a Java port of FastLZ compression +and decompression library written by William Kinney. It can be obtained at: + + * LICENSE: + * license/LICENSE.jfastlz.txt (MIT License) + * HOMEPAGE: + * https://code.google.com/p/jfastlz/ + +This product contains a modified portion of and optionally depends on 'Protocol Buffers', Google's data +interchange format, which can be obtained at: + + * LICENSE: + * license/LICENSE.protobuf.txt (New BSD License) + * HOMEPAGE: + * https://github.com/google/protobuf + +This product optionally depends on 'Bouncy Castle Crypto APIs' to generate +a temporary self-signed X.509 certificate when the JVM does not provide the +equivalent functionality. It can be obtained at: + + * LICENSE: + * license/LICENSE.bouncycastle.txt (MIT License) + * HOMEPAGE: + * http://www.bouncycastle.org/ + +This product optionally depends on 'Snappy', a compression library produced +by Google Inc, which can be obtained at: + + * LICENSE: + * license/LICENSE.snappy.txt (New BSD License) + * HOMEPAGE: + * https://github.com/google/snappy + +This product optionally depends on 'JBoss Marshalling', an alternative Java +serialization API, which can be obtained at: + + * LICENSE: + * license/LICENSE.jboss-marshalling.txt (GNU LGPL 2.1) + * HOMEPAGE: + * http://www.jboss.org/jbossmarshalling + +This product optionally depends on 'Caliper', Google's micro- +benchmarking framework, which can be obtained at: + + * LICENSE: + * license/LICENSE.caliper.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/google/caliper + +This product optionally depends on 'Apache Commons Logging', a logging +framework, which can be obtained at: + + * LICENSE: + * license/LICENSE.commons-logging.txt (Apache License 2.0) + * HOMEPAGE: + * http://commons.apache.org/logging/ + +This product optionally depends on 'Apache Log4J', a logging framework, which +can be obtained at: + + * LICENSE: + * license/LICENSE.log4j.txt (Apache License 2.0) + * HOMEPAGE: + * http://logging.apache.org/log4j/ + +This product optionally depends on 'Aalto XML', an ultra-high performance +non-blocking XML processor, which can be obtained at: + + * LICENSE: + * license/LICENSE.aalto-xml.txt (Apache License 2.0) + * HOMEPAGE: + * http://wiki.fasterxml.com/AaltoHome + +This product contains a modified version of 'HPACK', a Java implementation of +the HTTP/2 HPACK algorithm written by Twitter. It can be obtained at: + + * LICENSE: + * license/LICENSE.hpack.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/twitter/hpack + +This product contains a modified portion of 'Apache Commons Lang', a Java library +provides utilities for the java.lang API, which can be obtained at: + + * LICENSE: + * license/LICENSE.commons-lang.txt (Apache License 2.0) + * HOMEPAGE: + * https://commons.apache.org/proper/commons-lang/ + + +This product contains the Maven wrapper scripts from 'Maven Wrapper', that provides an easy way to ensure a user has everything necessary to run the Maven build. + + * LICENSE: + * license/LICENSE.mvn-wrapper.txt (Apache License 2.0) + * HOMEPAGE: + * https://github.com/takari/maven-wrapper + diff --git a/cook-async-agent/hippo4j-agent/plugins/cook-async-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar b/cook-async-agent/hippo4j-agent/plugins/cook-async-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar new file mode 100644 index 0000000000000000000000000000000000000000..53465dbaf869b2545903b76f6304513d2d58fd9a GIT binary patch literal 8285 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 + + + + 4.0.0 + + com.example + cook-frame + ${revision} + + cook-async-agent + pom + + + cook-async-agent-bootstrap + cook-async-agent-core + cook-async-agent-plugin + + + + com.example.agent.dependencies + UTF-8 + 1.8 + 4.13.1 + 2.0.7 + 3.5.13 + 1.18.20 + + + 1.12.13 + 1.44.0 + 4.1.79.Final + 2.8.9 + 1.6.2 + 1.3.2 + 3.1 + + 6.0.53 + + + 0.6.1 + 1.6.0 + 1.8 + 2.10 + 2.8.2 + 3.1.0 + 2.22.0 + 3.2.0 + 3.1.0 + 3.1.1 + 3.0.0-M2 + 3.8.0 + 3.1.0 + 3.0.1 + 2.5 + 4.3.0 + 3.1.0 + 1.33 + 1.5 + true + 1.7.25 + 30.1.1-jre + 2.16.0 + + + + + + com.google.code.gson + gson + ${gson.version} + + + com.google.guava + guava + ${guava.version} + + + net.bytebuddy + byte-buddy + ${bytebuddy.version} + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.openjdk.jmh + jmh-core + ${jmh.version} + test + + + org.projectlombok + lombok + ${lombok.version} + provided + + + javax.annotation + javax.annotation-api + ${javax.annotation-api.version} + provided + + + junit + junit + ${junit.version} + test + + + org.powermock + powermock-module-junit4 + ${powermock.version} + test + + + org.powermock + powermock-api-mockito2 + ${powermock.version} + test + + + net.bytebuddy + byte-buddy-agent + ${bytebuddy.version} + + + org.objenesis + objenesis + ${objenesis.version} + test + + + com.github.tomakehurst + wiremock + ${wiremock.version} + test + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + test + + + + + + ${project.artifactId}-${project.version} + + + + + + io.takari + maven + ${takari-maven-plugin.version} + + + maven-antrun-plugin + ${maven-antrun-plugin.version} + + + maven-deploy-plugin + ${maven-deploy-plugin.version} + + + maven-assembly-plugin + ${maven-assembly-plugin.version} + + + maven-failsafe-plugin + ${maven-failsafe-plugin.version} + + + maven-jar-plugin + ${maven-jar-plugin.version} + + true + + + + maven-shade-plugin + ${maven-shade-plugin.version} + + + + + + kr.motd.maven + os-maven-plugin + ${os-maven-plugin.version} + + + initialize + + detect + + + + + + maven-enforcer-plugin + ${maven-enforcer-plugin.version} + + + enforce-java + + enforce + + validate + + + + + 1.8 + + + + + + + + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${compiler.version} + ${compiler.version} + ${project.build.sourceEncoding} + + + + maven-resources-plugin + ${maven-resource-plugin.version} + + ${project.build.sourceEncoding} + + + + maven-source-plugin + ${maven-source-plugin.version} + + + attach-sources + none + + jar + + + + + + + diff --git a/distribute-es/src/test/java/com/example/DistributeEsApplicationTests.java b/distribute-es/src/test/java/com/example/DistributeEsApplicationTests.java deleted file mode 100644 index 1f87f927..00000000 --- a/distribute-es/src/test/java/com/example/DistributeEsApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.example; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class DistributeEsApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/id-generator/pom.xml b/id-generator/pom.xml index 6876a7cb..2c000050 100644 --- a/id-generator/pom.xml +++ b/id-generator/pom.xml @@ -48,6 +48,11 @@ org.springframework.boot spring-boot-starter-data-redis + + com.example + common + ${revision} + diff --git a/id-generator/src/test/java/com/example/IdGeneratorApplicationTests.java b/id-generator/src/test/java/com/example/IdGeneratorApplicationTests.java deleted file mode 100644 index 98fadf99..00000000 --- a/id-generator/src/test/java/com/example/IdGeneratorApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.example; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class IdGeneratorApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/pom.xml b/pom.xml index 2bb28d6b..75858067 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,7 @@ server server-client course-case + cook-async-agent @@ -50,77 +51,11 @@ 2.2.7.RELEASE - - org.springframework.boot - spring-boot-starter-aop - - - - org.springframework.boot - spring-boot-starter-test - test - - org.projectlombok lombok - - - com.alibaba - fastjson - 1.2.83 - - - org.springframework.boot - spring-boot-starter-log4j2 - - - org.slf4j - slf4j-log4j12 - - - org.apache.logging.log4j - log4j-core - - - - org.apache.logging.log4j - log4j-api - - - org.apache.logging.log4j - log4j-slf4j-impl - - - org.apache.logging.log4j - log4j-web - - - - - org.apache.logging.log4j - log4j-core - 2.17.0 - - - - org.apache.logging.log4j - log4j-api - 2.17.0 - - - org.apache.logging.log4j - log4j-slf4j-impl - 2.17.0 - - - org.apache.logging.log4j - log4j-web - 2.17.0 - - diff --git a/redis-tool/src/test/java/com/example/DistributeCacheApplicationTests.java b/redis-tool/src/test/java/com/example/DistributeCacheApplicationTests.java deleted file mode 100644 index 0b7312ed..00000000 --- a/redis-tool/src/test/java/com/example/DistributeCacheApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.example; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class DistributeCacheApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/server/server-case/src/main/java/com/example/controller/TestController.java b/server/server-case/src/main/java/com/example/controller/TestController.java new file mode 100644 index 00000000..7a87923f --- /dev/null +++ b/server/server-case/src/main/java/com/example/controller/TestController.java @@ -0,0 +1,30 @@ +package com.example.controller; + +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * @program: cook-frame + * @description: + * @author: k + * @create: 2023-07-21 + **/ +@RestController +@RequestMapping("/test") +public class TestController { + + private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1,1,60, TimeUnit.SECONDS,new ArrayBlockingQueue<>(30)); + + @PostMapping("test") + public String test(){ + threadPoolExecutor.execute(() -> { + System.out.println("22222"); + }); + return String.valueOf(2222); + } +} diff --git a/server/server-case/src/main/java/com/example/service/AccountService.java b/server/server-case/src/main/java/com/example/service/AccountService.java index 92d73d2d..d4e56918 100644 --- a/server/server-case/src/main/java/com/example/service/AccountService.java +++ b/server/server-case/src/main/java/com/example/service/AccountService.java @@ -1,6 +1,5 @@ package com.example.service; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.entity.Account; import com.example.mapper.AccountMapper; import org.springframework.beans.factory.annotation.Autowired; @@ -9,8 +8,12 @@ import org.springframework.transaction.annotation.Transactional; @Service @Transactional -public class AccountService extends ServiceImpl { +public class AccountService { @Autowired private AccountMapper accountMapper; + + public Account getById(String id){ + return accountMapper.selectById(id); + } } diff --git a/server/server-case/src/main/resources/mapper/AccountMapper.xml b/server/server-case/src/main/resources/mapper/AccountMapper.xml deleted file mode 100644 index cd8b7b9d..00000000 --- a/server/server-case/src/main/resources/mapper/AccountMapper.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file diff --git a/tool/pom.xml b/tool/pom.xml index ab1bd8eb..b9f53150 100644 --- a/tool/pom.xml +++ b/tool/pom.xml @@ -40,6 +40,10 @@ spring-boot-starter-web true + + org.springframework.boot + spring-boot-starter-aop + -- Gitee From 002fa92385e1975bbde811267d5c9ce818f3ba20 Mon Sep 17 00:00:00 2001 From: shining-stars-lk <1031900093@qq.com> Date: Fri, 21 Jul 2023 19:34:41 +0800 Subject: [PATCH 02/11] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AD=97=E8=8A=82?= =?UTF-8?q?=E7=A0=81=E5=A2=9E=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- ...agent-threadpool-plugin-0.0.1-SNAPSHOT.jar | Bin 0 -> 414165 bytes .../cook-async-agent-bootstrap/pom.xml | 12 +- .../agent/bootstrap/CookAsyncAgent.java | 263 +++++++++++ .../com/example/agent/core/base64/Base64.java | 41 ++ .../boot/AgentPackageNotFoundException.java | 25 ++ .../agent/core/boot/AgentPackagePath.java | 86 ++++ .../example/agent/core/boot/BootService.java | 42 ++ .../agent/core/boot/DefaultImplementor.java | 28 ++ .../core/boot/DefaultNamedThreadFactory.java | 39 ++ .../agent/core/boot/OverrideImplementor.java | 30 ++ .../example/agent/core/boot/PluginConfig.java | 39 ++ .../core/boot/ServiceConflictException.java | 25 ++ .../agent/core/boot/ServiceManager.java | 149 +++++++ .../boot/SpringBootConfigInitializer.java | 88 ++++ .../agent/core/boot/SpringBootConfigNode.java | 33 ++ .../com/example/agent/core/conf/Config.java | 407 ++++++++++++++++++ .../core/conf/ConfigNotFoundException.java | 29 ++ .../example/agent/core/conf/Constants.java | 39 ++ .../conf/RuntimeContextConfiguration.java | 27 ++ .../core/conf/SnifferConfigInitializer.java | 236 ++++++++++ .../dynamic/AgentConfigChangeWatcher.java | 63 +++ .../core/jvm/LoadedLibraryCollector.java | 132 ++++++ .../example/agent/core/logging/api/ILog.java | 63 +++ .../agent/core/logging/api/LogManager.java | 56 +++ .../agent/core/logging/api/LogResolver.java | 37 ++ .../agent/core/logging/api/NoopLogger.java | 122 ++++++ .../core/logging/core/AbstractLogger.java | 223 ++++++++++ .../agent/core/logging/core/Converter.java | 29 ++ .../agent/core/logging/core/FileWriter.java | 234 ++++++++++ .../agent/core/logging/core/IWriter.java | 23 + .../core/logging/core/JsonLogResolver.java | 38 ++ .../agent/core/logging/core/JsonLogger.java | 80 ++++ .../agent/core/logging/core/LogEvent.java | 68 +++ .../agent/core/logging/core/LogLevel.java | 22 + .../core/logging/core/LogMessageHolder.java | 35 ++ .../agent/core/logging/core/LogOutput.java | 22 + .../agent/core/logging/core/Parser.java | 190 ++++++++ .../core/logging/core/PatternLogResolver.java | 36 ++ .../core/logging/core/PatternLogger.java | 65 +++ .../agent/core/logging/core/ResolverType.java | 22 + .../core/logging/core/SystemOutWriter.java | 34 ++ .../core/logging/core/WriterFactory.java | 59 +++ .../core/converters/AgentNameConverter.java | 36 ++ .../core/converters/ClassConverter.java | 38 ++ .../core/converters/DateConverter.java | 41 ++ .../core/converters/LevelConverter.java | 37 ++ .../core/converters/LiteralConverter.java | 44 ++ .../core/converters/MessageConverter.java | 38 ++ .../core/converters/ThreadConverter.java | 38 ++ .../core/converters/ThrowableConverter.java | 55 +++ .../com/example/agent/core/os/OSUtil.java | 104 +++++ .../example/agent/core/os/ProcessorUtil.java | 27 ++ .../AbstractClassEnhancePluginDefine.java | 202 +++++++++ .../core/plugin/ByteBuddyCoreClasses.java | 36 ++ .../core/plugin/DynamicPluginLoader.java | 45 ++ .../agent/core/plugin/EnhanceContext.java | 51 +++ .../core/plugin/InstrumentDebuggingClass.java | 72 ++++ .../agent/core/plugin/PluginBootstrap.java | 81 ++++ .../example/agent/core/plugin/PluginCfg.java | 65 +++ .../agent/core/plugin/PluginDefine.java | 62 +++ .../agent/core/plugin/PluginException.java | 31 ++ .../agent/core/plugin/PluginFinder.java | 121 ++++++ .../core/plugin/PluginResourcesResolver.java | 55 +++ .../agent/core/plugin/PluginSelector.java | 49 +++ .../agent/core/plugin/WitnessFinder.java | 84 ++++ .../agent/core/plugin/WitnessMethod.java | 44 ++ .../bootstrap/BootstrapInstrumentBoost.java | 301 +++++++++++++ .../bootstrap/BootstrapPluginLogBridge.java | 102 +++++ .../core/plugin/bootstrap/IBootstrapLog.java | 52 +++ .../template/ConstructorInterTemplate.java | 79 ++++ .../template/InstanceMethodInterTemplate.java | 125 ++++++ ...ceMethodInterWithOverrideArgsTemplate.java | 125 ++++++ .../template/StaticMethodInterTemplate.java | 114 +++++ ...icMethodInterWithOverrideArgsTemplate.java | 114 +++++ .../v2/InstanceMethodInterV2Template.java | 128 ++++++ ...MethodInterV2WithOverrideArgsTemplate.java | 128 ++++++ .../v2/StaticMethodInterV2Template.java | 117 +++++ ...MethodInterV2WithOverrideArgsTemplate.java | 117 +++++ .../plugin/bytebuddy/AbstractJunction.java | 33 ++ .../bytebuddy/AnnotationTypeNameMatch.java | 70 +++ .../bytebuddy/ArgumentTypeNameMatch.java | 82 ++++ .../bytebuddy/ArrayTypeNameChecker.java | 27 ++ .../CacheableTransformerDecorator.java | 195 +++++++++ .../core/plugin/bytebuddy/ClassCacheMode.java | 25 ++ .../plugin/bytebuddy/ReturnTypeNameMatch.java | 65 +++ .../IllegalPluginDefineException.java | 28 ++ .../ConstructorInterceptPoint.java | 44 ++ ...DeclaredInstanceMethodsInterceptPoint.java | 25 ++ .../plugin/interceptor/EnhanceException.java | 33 ++ .../InstanceMethodsInterceptPoint.java | 45 ++ .../StaticMethodsInterceptPoint.java | 45 ++ .../enhance/BootstrapInterRuntimeAssist.java | 75 ++++ .../enhance/ClassEnhancePluginDefine.java | 238 ++++++++++ ...assInstanceMethodsEnhancePluginDefine.java | 38 ++ ...ClassStaticMethodsEnhancePluginDefine.java | 46 ++ .../interceptor/enhance/ConstructorInter.java | 71 +++ .../interceptor/enhance/EnhancedInstance.java | 25 ++ .../interceptor/enhance/InstMethodsInter.java | 105 +++++ .../InstMethodsInterWithOverrideArgs.java | 104 +++++ .../InstanceConstructorInterceptor.java | 31 ++ .../InstanceMethodsAroundInterceptor.java | 52 +++ .../enhance/MethodInterceptResult.java | 59 +++ .../interceptor/enhance/OverrideCallable.java | 23 + .../StaticMethodsAroundInterceptor.java | 51 +++ .../enhance/StaticMethodsInter.java | 102 +++++ .../StaticMethodsInterWithOverrideArgs.java | 101 +++++ .../v2/ClassEnhancePluginDefineV2.java | 207 +++++++++ ...sInstanceMethodsEnhancePluginDefineV2.java | 37 ++ ...assStaticMethodsEnhancePluginDefineV2.java | 46 ++ .../enhance/v2/InstMethodsInterV2.java | 87 ++++ .../InstMethodsInterV2WithOverrideArgs.java | 106 +++++ .../InstanceMethodsAroundInterceptorV2.java | 56 +++ .../enhance/v2/MethodInvocationContext.java | 35 ++ .../v2/StaticMethodsAroundInterceptorV2.java | 52 +++ .../enhance/v2/StaticMethodsInterV2.java | 102 +++++ .../StaticMethodsInterV2WithOverrideArgs.java | 102 +++++ .../v2/ConstructorInterceptV2Point.java | 38 ++ ...claredInstanceMethodsInterceptV2Point.java | 25 ++ .../v2/InstanceMethodsInterceptV2Point.java | 46 ++ .../v2/StaticMethodsInterceptV2Point.java | 46 ++ .../plugin/jdk9module/JDK9ModuleExporter.java | 89 ++++ .../core/plugin/loader/AgentClassLoader.java | 225 ++++++++++ .../plugin/loader/InstrumentationLoader.java | 31 ++ .../loader/InterceptorInstanceLoader.java | 79 ++++ .../plugin/match/ClassAnnotationMatch.java | 79 ++++ .../agent/core/plugin/match/ClassMatch.java | 21 + .../core/plugin/match/HierarchyMatch.java | 102 +++++ .../core/plugin/match/IndirectMatch.java | 31 ++ .../plugin/match/MethodAnnotationMatch.java | 88 ++++ .../MethodInheritanceAnnotationMatcher.java | 100 +++++ .../plugin/match/MultiClassNameMatch.java | 63 +++ .../agent/core/plugin/match/NameMatch.java | 38 ++ .../agent/core/plugin/match/PrefixMatch.java | 67 +++ .../plugin/match/ProtectiveShieldMatcher.java | 55 +++ .../agent/core/plugin/match/RegexMatch.java | 67 +++ .../plugin/match/logical/LogicalAndMatch.java | 66 +++ .../match/logical/LogicalMatchOperation.java | 52 +++ .../plugin/match/logical/LogicalOrMatch.java | 66 +++ .../core/util/AgentThreadPoolConstants.java | 27 ++ .../agent/core/util/CollectionUtil.java | 64 +++ .../agent/core/util/ConfigInitializer.java | 213 +++++++++ .../agent/core/util/CustomizeExpression.java | 120 ++++++ .../agent/core/util/ExecutorNameUtil.java | 44 ++ .../example/agent/core/util/FileUtils.java | 57 +++ .../com/example/agent/core/util/IOUtils.java | 145 +++++++ .../com/example/agent/core/util/Length.java | 33 ++ .../example/agent/core/util/MethodUtil.java | 83 ++++ .../util/PlaceholderConfigurerSupport.java | 37 ++ .../agent/core/util/PrivateKeyUtil.java | 81 ++++ .../core/util/PropertyPlaceholderHelper.java | 208 +++++++++ .../example/agent/core/util/ReflectUtil.java | 44 ++ .../example/agent/core/util/RegexUtil.java | 30 ++ .../util/RunnableWithExceptionProtection.java | 43 ++ .../example/agent/core/util/StringUtil.java | 110 +++++ .../core/util/ThreadPoolPropertyKey.java | 39 ++ .../pom.xml | 10 + .../AbstractThreadingPoolInterceptor.java | 66 +++ .../ThreadPoolExecuteMethodInterceptor.java | 53 +++ .../ThreadPoolSubmitMethodInterceptor.java | 49 +++ .../ThreadPoolExecutorInstrumentation.java | 97 +++++ .../plugin/thread/wrapper/BaseWrapper.java | 48 +++ .../thread/wrapper/CallableWrapper.java | 42 ++ .../thread/wrapper/RunnableWrapper.java | 41 ++ .../cook-async-agent-plugin/pom.xml | 2 +- pom.xml | 1 + threadlocal-tool/.gitignore | 31 ++ threadlocal-tool/mvnw | 310 +++++++++++++ threadlocal-tool/mvnw.cmd | 182 ++++++++ threadlocal-tool/pom.xml | 44 ++ .../java/com/example/ParameterHolder.java | 57 +++ 171 files changed, 12796 insertions(+), 8 deletions(-) create mode 100644 cook-async-agent/agent/plugins/cook-async-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar create mode 100644 cook-async-agent/cook-async-agent-bootstrap/src/main/java/com/example/agent/bootstrap/CookAsyncAgent.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/base64/Base64.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/AgentPackageNotFoundException.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/AgentPackagePath.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/BootService.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/DefaultImplementor.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/DefaultNamedThreadFactory.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/OverrideImplementor.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/PluginConfig.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/ServiceConflictException.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/ServiceManager.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/SpringBootConfigInitializer.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/SpringBootConfigNode.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/Config.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/ConfigNotFoundException.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/Constants.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/RuntimeContextConfiguration.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/SnifferConfigInitializer.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/dynamic/AgentConfigChangeWatcher.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/jvm/LoadedLibraryCollector.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/api/ILog.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/api/LogManager.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/api/LogResolver.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/api/NoopLogger.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/AbstractLogger.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/Converter.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/FileWriter.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/IWriter.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/JsonLogResolver.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/JsonLogger.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/LogEvent.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/LogLevel.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/LogMessageHolder.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/LogOutput.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/Parser.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/PatternLogResolver.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/PatternLogger.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/ResolverType.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/SystemOutWriter.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/WriterFactory.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/AgentNameConverter.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/ClassConverter.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/DateConverter.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/LevelConverter.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/LiteralConverter.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/MessageConverter.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/ThreadConverter.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/ThrowableConverter.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/os/OSUtil.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/os/ProcessorUtil.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/AbstractClassEnhancePluginDefine.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/ByteBuddyCoreClasses.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/DynamicPluginLoader.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/EnhanceContext.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/InstrumentDebuggingClass.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginBootstrap.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginCfg.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginDefine.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginException.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginFinder.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginResourcesResolver.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginSelector.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/WitnessFinder.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/WitnessMethod.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/BootstrapInstrumentBoost.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/BootstrapPluginLogBridge.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/IBootstrapLog.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/ConstructorInterTemplate.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/InstanceMethodInterTemplate.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/InstanceMethodInterWithOverrideArgsTemplate.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/StaticMethodInterTemplate.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/StaticMethodInterWithOverrideArgsTemplate.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/v2/InstanceMethodInterV2Template.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/v2/InstanceMethodInterV2WithOverrideArgsTemplate.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/v2/StaticMethodInterV2Template.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/v2/StaticMethodInterV2WithOverrideArgsTemplate.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/AbstractJunction.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/AnnotationTypeNameMatch.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/ArgumentTypeNameMatch.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/ArrayTypeNameChecker.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/CacheableTransformerDecorator.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/ClassCacheMode.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/ReturnTypeNameMatch.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/exception/IllegalPluginDefineException.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/ConstructorInterceptPoint.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/DeclaredInstanceMethodsInterceptPoint.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/EnhanceException.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/InstanceMethodsInterceptPoint.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/StaticMethodsInterceptPoint.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/BootstrapInterRuntimeAssist.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/ClassEnhancePluginDefine.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/ClassInstanceMethodsEnhancePluginDefine.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/ClassStaticMethodsEnhancePluginDefine.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/ConstructorInter.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/EnhancedInstance.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/InstMethodsInter.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/InstMethodsInterWithOverrideArgs.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/InstanceConstructorInterceptor.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/InstanceMethodsAroundInterceptor.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/MethodInterceptResult.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/OverrideCallable.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/StaticMethodsAroundInterceptor.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/StaticMethodsInter.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/StaticMethodsInterWithOverrideArgs.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/ClassEnhancePluginDefineV2.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/ClassInstanceMethodsEnhancePluginDefineV2.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/ClassStaticMethodsEnhancePluginDefineV2.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/InstMethodsInterV2.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/InstMethodsInterV2WithOverrideArgs.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/InstanceMethodsAroundInterceptorV2.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/MethodInvocationContext.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/StaticMethodsAroundInterceptorV2.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/StaticMethodsInterV2.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/StaticMethodsInterV2WithOverrideArgs.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/v2/ConstructorInterceptV2Point.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/v2/DeclaredInstanceMethodsInterceptV2Point.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/v2/InstanceMethodsInterceptV2Point.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/v2/StaticMethodsInterceptV2Point.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/jdk9module/JDK9ModuleExporter.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/loader/AgentClassLoader.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/loader/InstrumentationLoader.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/loader/InterceptorInstanceLoader.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/ClassAnnotationMatch.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/ClassMatch.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/HierarchyMatch.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/IndirectMatch.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/MethodAnnotationMatch.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/MethodInheritanceAnnotationMatcher.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/MultiClassNameMatch.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/NameMatch.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/PrefixMatch.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/ProtectiveShieldMatcher.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/RegexMatch.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/logical/LogicalAndMatch.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/logical/LogicalMatchOperation.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/logical/LogicalOrMatch.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/AgentThreadPoolConstants.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/CollectionUtil.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/ConfigInitializer.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/CustomizeExpression.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/ExecutorNameUtil.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/FileUtils.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/IOUtils.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/Length.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/MethodUtil.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/PlaceholderConfigurerSupport.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/PrivateKeyUtil.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/PropertyPlaceholderHelper.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/ReflectUtil.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/RegexUtil.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/RunnableWithExceptionProtection.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/StringUtil.java create mode 100644 cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/ThreadPoolPropertyKey.java create mode 100644 cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/AbstractThreadingPoolInterceptor.java create mode 100644 cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolExecuteMethodInterceptor.java create mode 100644 cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolSubmitMethodInterceptor.java create mode 100644 cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/define/ThreadPoolExecutorInstrumentation.java create mode 100644 cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/BaseWrapper.java create mode 100644 cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/CallableWrapper.java create mode 100644 cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/RunnableWrapper.java create mode 100644 threadlocal-tool/.gitignore create mode 100644 threadlocal-tool/mvnw create mode 100644 threadlocal-tool/mvnw.cmd create mode 100644 threadlocal-tool/pom.xml create mode 100644 threadlocal-tool/src/main/java/com/example/ParameterHolder.java diff --git a/.gitignore b/.gitignore index 3f895d09..1f3158b2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ target/ logs/ ### Agent ### -agent/ +cookasyncagent/ **/dependency-reduced-pom.xml ### STS ### diff --git a/cook-async-agent/agent/plugins/cook-async-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar b/cook-async-agent/agent/plugins/cook-async-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar new file mode 100644 index 0000000000000000000000000000000000000000..d714e30c8cfe2563bf6c25ccd3bd4234ae872768 GIT binary patch literal 414165 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 z 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%0D@X9bbI( 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 MQqQXo{x+VE|YOr-QcDNM%cay_~x&)MhEu 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 egAJZ~$axm%&xT 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 - - - - - - + + + + + + diff --git a/cook-async-agent/cook-async-agent-bootstrap/src/main/java/com/example/agent/bootstrap/CookAsyncAgent.java b/cook-async-agent/cook-async-agent-bootstrap/src/main/java/com/example/agent/bootstrap/CookAsyncAgent.java new file mode 100644 index 00000000..b318a095 --- /dev/null +++ b/cook-async-agent/cook-async-agent-bootstrap/src/main/java/com/example/agent/bootstrap/CookAsyncAgent.java @@ -0,0 +1,263 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.bootstrap; + +import com.example.agent.core.boot.AgentPackageNotFoundException; +import com.example.agent.core.boot.ServiceManager; +import com.example.agent.core.conf.Config; +import com.example.agent.core.conf.SnifferConfigInitializer; +import com.example.agent.core.jvm.LoadedLibraryCollector; +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.AbstractClassEnhancePluginDefine; +import com.example.agent.core.plugin.EnhanceContext; +import com.example.agent.core.plugin.InstrumentDebuggingClass; +import com.example.agent.core.plugin.PluginBootstrap; +import com.example.agent.core.plugin.PluginException; +import com.example.agent.core.plugin.PluginFinder; +import com.example.agent.core.plugin.bootstrap.BootstrapInstrumentBoost; +import com.example.agent.core.plugin.bytebuddy.CacheableTransformerDecorator; +import com.example.agent.core.plugin.jdk9module.JDK9ModuleExporter; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.description.NamedElement; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.DynamicType; +import net.bytebuddy.dynamic.scaffold.TypeValidation; +import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.ElementMatchers; +import net.bytebuddy.utility.JavaModule; + +import java.lang.instrument.Instrumentation; +import java.security.ProtectionDomain; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static net.bytebuddy.matcher.ElementMatchers.nameContains; +import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; +import static net.bytebuddy.matcher.ElementMatchers.not; + +/** + * cook Agent + */ +public class CookAsyncAgent { + + private static ILog LOGGER = LogManager.getLogger(CookAsyncAgent.class); + + /** + * Main entrance. Use byte-buddy transform to enhance all classes, which define in plugins. + */ + public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException { + final PluginFinder pluginFinder; + try { + SnifferConfigInitializer.initializeCoreConfig(agentArgs); + } catch (Exception e) { + // try to resolve a new logger, and use the new logger to write the error log here + LogManager.getLogger(CookAsyncAgent.class) + .error(e, "cook-async agent initialized failure. Shutting down."); + return; + } finally { + // refresh logger again after initialization finishes + LOGGER = LogManager.getLogger(CookAsyncAgent.class); + } + + try { + pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins()); + } catch (AgentPackageNotFoundException ape) { + LOGGER.error(ape, "Locate agent.jar failure. Shutting down."); + return; + } catch (Exception e) { + LOGGER.error(e, "cook-async agent initialized failure. Shutting down."); + return; + } + + final ByteBuddy byteBuddy = new ByteBuddy().with(TypeValidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS)); + + AgentBuilder agentBuilder = new AgentBuilder.Default(byteBuddy).ignore( + nameStartsWith("net.bytebuddy.") + .or(nameStartsWith("org.slf4j.")) + .or(nameStartsWith("org.groovy.")) + .or(nameContains("javassist")) + .or(nameContains(".asm.")) + .or(nameContains(".reflectasm.")) + .or(nameStartsWith("sun.reflect")) + .or(allCookAsyncAgentExcludeToolkit()) + .or(ElementMatchers.isSynthetic())); + + JDK9ModuleExporter.EdgeClasses edgeClasses = new JDK9ModuleExporter.EdgeClasses(); + try { + agentBuilder = BootstrapInstrumentBoost.inject(pluginFinder, instrumentation, agentBuilder, edgeClasses); + } catch (Exception e) { + LOGGER.error(e, "cook-async agent inject bootstrap instrumentation failure. Shutting down."); + return; + } + + try { + agentBuilder = JDK9ModuleExporter.openReadEdge(instrumentation, agentBuilder, edgeClasses); + } catch (Exception e) { + LOGGER.error(e, "cook-async agent open read edge in JDK 9+ failure. Shutting down."); + return; + } + + if (Config.Agent.IS_CACHE_ENHANCED_CLASS) { + try { + agentBuilder = agentBuilder.with(new CacheableTransformerDecorator(Config.Agent.CLASS_CACHE_MODE)); + LOGGER.info("cook-async agent class cache [{}] activated.", Config.Agent.CLASS_CACHE_MODE); + } catch (Exception e) { + LOGGER.error(e, "cook-async agent can't active class cache."); + } + } + + agentBuilder.type(pluginFinder.buildMatch()) + .transform(new Transformer(pluginFinder)) + .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) + .with(new RedefinitionListener()) + .with(new Listener()) + .installOn(instrumentation); + + PluginFinder.pluginInitCompleted(); + + try { + ServiceManager.INSTANCE.boot(); + } catch (Exception e) { + LOGGER.error(e, "cook-async agent boot failure."); + } + +// try { +// Class.forName("java.util.concurrent.ThreadPoolExecutor"); +// } catch (ClassNotFoundException e) { +// LOGGER.error(e, "cook-async agent boot failure."); +// } + + Runtime.getRuntime() + .addShutdownHook(new Thread(ServiceManager.INSTANCE::shutdown, "cook-async service shutdown thread")); + } + + /** + * transformer + */ + private static class Transformer implements AgentBuilder.Transformer { + + private PluginFinder pluginFinder; + + Transformer(PluginFinder pluginFinder) { + this.pluginFinder = pluginFinder; + } + + @Override + public DynamicType.Builder transform(final DynamicType.Builder builder, + final TypeDescription typeDescription, + final ClassLoader classLoader, + final JavaModule javaModule, + final ProtectionDomain protectionDomain) { + LoadedLibraryCollector.registerURLClassLoader(classLoader); + List pluginDefines = pluginFinder.find(typeDescription); + if (pluginDefines.size() > 0) { + DynamicType.Builder newBuilder = builder; + EnhanceContext context = new EnhanceContext(); + for (AbstractClassEnhancePluginDefine define : pluginDefines) { + DynamicType.Builder possibleNewBuilder = define.define( + typeDescription, newBuilder, classLoader, context); + if (possibleNewBuilder != null) { + newBuilder = possibleNewBuilder; + } + } + if (context.isEnhanced()) { + LOGGER.debug("Finish the prepare stage for {}.", typeDescription.getName()); + } + + return newBuilder; + } + + LOGGER.debug("Matched class {}, but ignore by finding mechanism.", typeDescription.getTypeName()); + return builder; + } + } + + private static ElementMatcher.Junction allCookAsyncAgentExcludeToolkit() { + return nameStartsWith("com.example").and(not(nameStartsWith("com.example.agent.toolkit."))); + } + + /** + * listener + */ + private static class Listener implements AgentBuilder.Listener { + + @Override + public void onDiscovery(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) { + + } + + @Override + public void onTransformation(final TypeDescription typeDescription, + final ClassLoader classLoader, + final JavaModule module, + final boolean loaded, + final DynamicType dynamicType) { + if (LOGGER.isDebugEnable()) { + LOGGER.debug("On Transformation class {}.", typeDescription.getName()); + } + + InstrumentDebuggingClass.INSTANCE.log(dynamicType); + } + + @Override + public void onIgnored(final TypeDescription typeDescription, + final ClassLoader classLoader, + final JavaModule module, + final boolean loaded) { + + } + + @Override + public void onError(final String typeName, + final ClassLoader classLoader, + final JavaModule module, + final boolean loaded, + final Throwable throwable) { + LOGGER.error("Enhance class " + typeName + " error.", throwable); + } + + @Override + public void onComplete(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) { + } + } + + /** + * redefinition listener + */ + private static class RedefinitionListener implements AgentBuilder.RedefinitionStrategy.Listener { + + @Override + public void onBatch(int index, List> batch, List> types) { + /* do nothing */ + } + + @Override + public Iterable>> onError(int index, List> batch, Throwable throwable, List> types) { + LOGGER.error(throwable, "index={}, batch={}, types={}", index, batch, types); + return Collections.emptyList(); + } + + @Override + public void onComplete(int amount, List> types, Map>, Throwable> failures) { + /* do nothing */ + } + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/base64/Base64.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/base64/Base64.java new file mode 100644 index 00000000..681af8e6 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/base64/Base64.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.base64; + +import java.nio.charset.StandardCharsets; + +/** + * A wrapper of {@link java.util.Base64} with convenient conversion methods between {@code byte[]} and {@code String} + */ +public final class Base64 { + + private static final java.util.Base64.Decoder DECODER = java.util.Base64.getDecoder(); + private static final java.util.Base64.Encoder ENCODER = java.util.Base64.getEncoder(); + + private Base64() { + } + + public static String decode2UTFString(String in) { + return new String(DECODER.decode(in), StandardCharsets.UTF_8); + } + + public static String encode(String text) { + return ENCODER.encodeToString(text.getBytes(StandardCharsets.UTF_8)); + } + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/AgentPackageNotFoundException.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/AgentPackageNotFoundException.java new file mode 100644 index 00000000..e527983d --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/AgentPackageNotFoundException.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.boot; + +public class AgentPackageNotFoundException extends Exception { + + public AgentPackageNotFoundException(String message) { + super(message); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/AgentPackagePath.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/AgentPackagePath.java new file mode 100644 index 00000000..60fae3a6 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/AgentPackagePath.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.boot; + + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; + +/** + * AgentPackagePath is a flag and finder to locate the cook-async agent.jar. It gets the absolute path of the agent jar. + * The path is the required metadata for agent core looking up the plugins and toolkit activations. If the lookup + * mechanism fails, the agent will exit directly. + */ +public class AgentPackagePath { + + private static final ILog LOGGER = LogManager.getLogger(AgentPackagePath.class); + + private static File AGENT_PACKAGE_PATH; + + public static File getPath() throws AgentPackageNotFoundException { + if (AGENT_PACKAGE_PATH == null) { + AGENT_PACKAGE_PATH = findPath(); + } + return AGENT_PACKAGE_PATH; + } + + public static boolean isPathFound() { + return AGENT_PACKAGE_PATH != null; + } + + private static File findPath() throws AgentPackageNotFoundException { + String classResourcePath = AgentPackagePath.class.getName().replaceAll("\\.", "/") + ".class"; + + URL resource = ClassLoader.getSystemClassLoader().getResource(classResourcePath); + if (resource != null) { + String urlString = resource.toString(); + + LOGGER.debug("The beacon class location is {}.", urlString); + + int insidePathIndex = urlString.indexOf('!'); + boolean isInJar = insidePathIndex > -1; + + if (isInJar) { + urlString = urlString.substring(urlString.indexOf("file:"), insidePathIndex); + File agentJarFile = null; + try { + agentJarFile = new File(new URL(urlString).toURI()); + } catch (MalformedURLException | URISyntaxException e) { + LOGGER.error(e, "Can not locate agent jar file by url:" + urlString); + } + if (agentJarFile.exists()) { + return agentJarFile.getParentFile(); + } + } else { + int prefixLength = "file:".length(); + String classLocation = urlString.substring( + prefixLength, urlString.length() - classResourcePath.length()); + return new File(classLocation); + } + } + + LOGGER.error("Can not locate agent jar file."); + throw new AgentPackageNotFoundException("Can not locate agent jar file."); + } + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/BootService.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/BootService.java new file mode 100644 index 00000000..57ba4e97 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/BootService.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.boot; + +/** + * The BootService is an interface to all remote, which need to boot when plugin mechanism begins to work. + * {@link #boot()} will be called when BootService start up. + */ +public interface BootService { + + void prepare() throws Throwable; + + void boot() throws Throwable; + + void onComplete() throws Throwable; + + void shutdown() throws Throwable; + + /** + * {@code BootService}s with higher priorities will be started earlier, and shut down later than those {@code BootService}s with lower priorities. + * + * @return the priority of this {@code BootService}. + */ + default int priority() { + return 0; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/DefaultImplementor.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/DefaultImplementor.java new file mode 100644 index 00000000..23ee7f3a --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/DefaultImplementor.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.boot; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface DefaultImplementor { +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/DefaultNamedThreadFactory.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/DefaultNamedThreadFactory.java new file mode 100644 index 00000000..fb67c63f --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/DefaultNamedThreadFactory.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.boot; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +public class DefaultNamedThreadFactory implements ThreadFactory { + + private static final AtomicInteger BOOT_SERVICE_SEQ = new AtomicInteger(0); + private final AtomicInteger threadSeq = new AtomicInteger(0); + private final String namePrefix; + + public DefaultNamedThreadFactory(String name) { + namePrefix = "Cook-Async-jAgent-" + BOOT_SERVICE_SEQ.incrementAndGet() + "-" + name + "-"; + } + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r, namePrefix + threadSeq.getAndIncrement()); + t.setDaemon(true); + return t; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/OverrideImplementor.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/OverrideImplementor.java new file mode 100644 index 00000000..0171ddae --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/OverrideImplementor.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.boot; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface OverrideImplementor { + + Class value(); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/PluginConfig.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/PluginConfig.java new file mode 100644 index 00000000..6fe60851 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/PluginConfig.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.boot; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * ConfigInitializationService provides the config class which should host all parameters originally from agent setup. + * {@link com.example.agent.core.conf.Config} provides the core level config, all plugins could implement + * this interface to have the same capability about initializing config from agent.config, system properties and system + * environment variables. + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface PluginConfig { + + /** + * @return Class as the root to do config initialization. + */ + Class root(); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/ServiceConflictException.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/ServiceConflictException.java new file mode 100644 index 00000000..73198ca6 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/ServiceConflictException.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.boot; + +public class ServiceConflictException extends RuntimeException { + + public ServiceConflictException(String message) { + super(message); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/ServiceManager.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/ServiceManager.java new file mode 100644 index 00000000..d64cdc9b --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/ServiceManager.java @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.boot; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.loader.AgentClassLoader; + +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; + +/** + * The ServiceManager bases on {@link ServiceLoader}, load all {@link BootService} implementations. + */ +public enum ServiceManager { + + INSTANCE; + + private static final ILog LOGGER = LogManager.getLogger(ServiceManager.class); + private Map bootedServices = Collections.emptyMap(); + + public void boot() { + bootedServices = loadAllServices(); + + prepare(); + startup(); + onComplete(); + } + + public void shutdown() { + bootedServices.values().stream().sorted(Comparator.comparingInt(BootService::priority).reversed()).forEach(service -> { + try { + service.shutdown(); + } catch (Throwable e) { + LOGGER.error(e, "ServiceManager try to shutdown [{}] fail.", service.getClass().getName()); + } + }); + } + + private Map loadAllServices() { + Map bootedServices = new LinkedHashMap<>(); + List allServices = new LinkedList<>(); + load(allServices); + for (final BootService bootService : allServices) { + Class bootServiceClass = bootService.getClass(); + boolean isDefaultImplementor = bootServiceClass.isAnnotationPresent(DefaultImplementor.class); + if (isDefaultImplementor) { + if (!bootedServices.containsKey(bootServiceClass)) { + bootedServices.put(bootServiceClass, bootService); + } else { + // ignore the default service + } + } else { + OverrideImplementor overrideImplementor = bootServiceClass.getAnnotation(OverrideImplementor.class); + if (overrideImplementor == null) { + if (!bootedServices.containsKey(bootServiceClass)) { + bootedServices.put(bootServiceClass, bootService); + } else { + throw new ServiceConflictException("Duplicate service define for :" + bootServiceClass); + } + } else { + Class targetService = overrideImplementor.value(); + if (bootedServices.containsKey(targetService)) { + boolean presentDefault = bootedServices.get(targetService) + .getClass() + .isAnnotationPresent(DefaultImplementor.class); + if (presentDefault) { + bootedServices.put(targetService, bootService); + } else { + throw new ServiceConflictException( + "Service " + bootServiceClass + " overrides conflict, " + "exist more than one service want to override :" + targetService); + } + } else { + bootedServices.put(targetService, bootService); + } + } + } + + } + return bootedServices; + } + + private void prepare() { + bootedServices.values().stream().sorted(Comparator.comparingInt(BootService::priority)).forEach(service -> { + try { + service.prepare(); + } catch (Throwable e) { + LOGGER.error(e, "ServiceManager try to pre-start [{}] fail.", service.getClass().getName()); + } + }); + } + + private void startup() { + bootedServices.values().stream().sorted(Comparator.comparingInt(BootService::priority)).forEach(service -> { + try { + service.boot(); + } catch (Throwable e) { + LOGGER.error(e, "ServiceManager try to start [{}] fail.", service.getClass().getName()); + } + }); + } + + private void onComplete() { + for (BootService service : bootedServices.values()) { + try { + service.onComplete(); + } catch (Throwable e) { + LOGGER.error(e, "Service [{}] AfterBoot process fails.", service.getClass().getName()); + } + } + } + + /** + * Find a {@link BootService} implementation, which is already started. + * + * @param serviceClass class name. + * @param {@link BootService} implementation class. + * @return {@link BootService} instance + */ + public T findService(Class serviceClass) { + return (T) bootedServices.get(serviceClass); + } + + void load(List allServices) { + for (final BootService bootService : ServiceLoader.load(BootService.class, AgentClassLoader.getDefault())) { + allServices.add(bootService); + } + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/SpringBootConfigInitializer.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/SpringBootConfigInitializer.java new file mode 100644 index 00000000..750fb595 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/SpringBootConfigInitializer.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.boot; + + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.util.ConfigInitializer; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; + +public class SpringBootConfigInitializer { + + private static final ILog LOG = LogManager.getLogger(SpringBootConfigInitializer.class); + + private static final Set> SPRING_BOOT_CONFIG_LIST = Collections.synchronizedSet(new HashSet<>()); + + private static final long MAX_CACHE_TIME = 30L * 60L * 1000L; // half an hour. + + private static final int MAX_CACHE_SIZE = 1000; + + private static long PROPERTIES_LOAD_TIME; + + public static Properties SPRING_PROPERTIES = null; + + private SpringBootConfigInitializer() { + + } + + public static boolean isSpringPropertiesEmpty() { + return SPRING_PROPERTIES == null || SPRING_PROPERTIES.isEmpty(); + } + + public static synchronized void initializeConfig(SpringBootConfigNode springBootConfig) { + if (SPRING_PROPERTIES != null) { + try { + LOG.info("initialize Spring Config Class {}.", springBootConfig.root()); + ConfigInitializer.initialize(SPRING_PROPERTIES, springBootConfig.root(), true); + } catch (Throwable e) { + LOG.error(e, "Failed to set the agent settings {} to Config={} ", SPRING_PROPERTIES, springBootConfig.root()); + } + } + boolean isStarting = PROPERTIES_LOAD_TIME == 0L; + boolean overtime = System.currentTimeMillis() - PROPERTIES_LOAD_TIME > MAX_CACHE_TIME; + boolean oversize = SPRING_BOOT_CONFIG_LIST.size() > MAX_CACHE_SIZE; + // avoid memory leak. + if (isStarting || (!oversize && !overtime)) { + SPRING_BOOT_CONFIG_LIST.add(springBootConfig.root()); + } else { + LOG.warn("spirng Config Class is skipped {}.", springBootConfig.root()); + } + } + + public static synchronized void setSpringProperties(Properties properties) { + if (properties != null && (SPRING_PROPERTIES == null || properties.size() > SPRING_PROPERTIES.size())) { + LOG.info("set Spring Config Properties before : {}.", SPRING_PROPERTIES); + SPRING_PROPERTIES = properties; + LOG.info("set Spring Config Properties after : {}.", SPRING_PROPERTIES); + PROPERTIES_LOAD_TIME = System.currentTimeMillis(); + } + for (Class clazz : SPRING_BOOT_CONFIG_LIST) { + try { + LOG.info("initialize Spring Config Class in loop {}.", clazz); + ConfigInitializer.initialize(SPRING_PROPERTIES, clazz); + } catch (Throwable e) { + LOG.error(e, "Failed to set the agent Config={} from settings {}", clazz, properties); + } + } + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/SpringBootConfigNode.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/SpringBootConfigNode.java new file mode 100644 index 00000000..a861e553 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/boot/SpringBootConfigNode.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.boot; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface SpringBootConfigNode { + + /** + * @return Class as the root to do config initialization. + */ + Class root(); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/Config.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/Config.java new file mode 100644 index 00000000..e99d95d6 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/Config.java @@ -0,0 +1,407 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.conf; + + +import com.example.agent.core.logging.core.LogLevel; +import com.example.agent.core.logging.core.LogOutput; +import com.example.agent.core.logging.core.ResolverType; +import com.example.agent.core.logging.core.WriterFactory; +import com.example.agent.core.plugin.bytebuddy.ClassCacheMode; +import com.example.agent.core.util.Length; + +import java.util.Arrays; +import java.util.List; + +/** + * This is the core config in cook-async agent. + */ +public class Config { + + public static class Agent { + + /** + * Namespace represents a subnet, such as kubernetes namespace, or 172.10.*.*. + * + * @since 8.10.0 namespace would be added as {@link #SERVICE_NAME} suffix. + * + * Removed namespace isolating headers in cross process propagation. The HEADER name was + * `HeaderName:Namespace`. + */ + @Length(20) + public static String NAMESPACE = ""; + + /** + * Service name is showed on the UI. Suggestion: set a unique name for each service, service instance nodes + * share the same code + * + * @since 8.10.0 ${service name} = [${group name}::]${logic name}|${NAMESPACE}|${CLUSTER} + * + * The group name, namespace and cluster are optional. Once they are all blank, service name would be the final + * name. + */ + @Length(50) + public static String SERVICE_NAME = ""; + + /** + * Cluster defines the physical cluster in a data center or same network segment. In one cluster, IP address + * should be unique identify. + * + * The cluster name would be + * + * 1. Add as {@link #SERVICE_NAME} suffix. + * + * 2. Add as exit span's peer, ${CLUSTER} / original peer + * + * 3. Cross Process Propagation Header's value addressUsedAtClient[index=8] (Target address of this request used + * on the client end). + * + * @since 8.10.0 + */ + @Length(20) + public static String CLUSTER = ""; + + /** + * Authentication active is based on backend setting, see application.yml for more details. For most scenarios, + * this needs backend extensions, only basic match auth provided in default implementation. + */ + public static String AUTHENTICATION = ""; + + /** + * If true, cook-async agent will save all instrumented classes files in `/debugging` folder. cook-async team + * may ask for these files in order to resolve compatible problem. + */ + public static boolean IS_OPEN_DEBUGGING_CLASS = false; + + /** + * If true, cook-async agent will cache all instrumented classes to memory or disk files (decided by class cache + * mode), allow other javaagent to enhance those classes that enhanced by cook-async agent. + */ + public static boolean IS_CACHE_ENHANCED_CLASS = false; + + /** + * The instrumented classes cache mode: MEMORY or FILE MEMORY: cache class bytes to memory, if instrumented + * classes is too many or too large, it may take up more memory FILE: cache class bytes in `/class-cache` + * folder, automatically clean up cached class files when the application exits + */ + public static ClassCacheMode CLASS_CACHE_MODE = ClassCacheMode.MEMORY; + + /** + * The identifier of the instance + */ + @Length(50) + public volatile static String INSTANCE_NAME = ""; + + /** + * service instance properties in json format. e.g. agent.instance_properties_json = {"org": + * "com.example"} + */ + public static String INSTANCE_PROPERTIES_JSON = ""; + + /** + * How depth the agent goes, when log cause exceptions. + */ + public static int CAUSE_EXCEPTION_DEPTH = 5; + + /** + * Force reconnection period of grpc, based on grpc_channel_check_interval. If count of check grpc channel + * status more than this number. The channel check will call channel.getState(true) to requestConnection. + */ + public static long FORCE_RECONNECTION_PERIOD = 1; + + /** + * Limit the length of the operationName to prevent the overlength issue in the storage. + * + *

NOTICE

+ * In the current practice, we don't recommend the length over 190. + */ + public static int OPERATION_NAME_THRESHOLD = 150; + + /** + * Keep tracing even the backend is not available. + */ + public static boolean KEEP_TRACING = false; + + /** + * Force open TLS for gRPC channel if true. + */ + public static boolean FORCE_TLS = false; + + /** + * SSL trusted ca file. If it exists, will enable TLS for gRPC channel. + */ + public static String SSL_TRUSTED_CA_PATH = "ca" + Constants.PATH_SEPARATOR + "ca.crt"; + + /** + * Key cert chain file. If ssl_cert_chain and ssl_key exist, will enable mTLS for gRPC channel. + */ + public static String SSL_CERT_CHAIN_PATH; + + /** + * Private key file. If ssl_cert_chain and ssl_key exist, will enable mTLS for gRPC channel. + */ + public static String SSL_KEY_PATH; + } + + public static class OsInfo { + + /** + * Limit the length of the ipv4 list size. + */ + public static int IPV4_LIST_SIZE = 10; + } + + public static class Collector { + + /** + * grpc channel status check interval + */ + public static long GRPC_CHANNEL_CHECK_INTERVAL = 30; + /** + * The period in which the agent report a heartbeat to the backend. + */ + public static long HEARTBEAT_PERIOD = 30; + /** + * The agent sends the instance properties to the backend every `collector.heartbeat_period * + * collector.properties_report_period_factor` seconds + */ + public static int PROPERTIES_REPORT_PERIOD_FACTOR = 10; + /** + * Collector cook-async trace receiver service addresses. + */ + public static String BACKEND_SERVICE = ""; + /** + * How long grpc client will timeout in sending data to upstream. + */ + public static int GRPC_UPSTREAM_TIMEOUT = 30; + /** + * Get profile task list interval + */ + public static int GET_PROFILE_TASK_INTERVAL = 20; + /** + * Get agent dynamic config interval + */ + public static int GET_AGENT_DYNAMIC_CONFIG_INTERVAL = 20; + /** + * If true, cook-async agent will enable periodically resolving DNS to update receiver service addresses. + */ + public static boolean IS_RESOLVE_DNS_PERIODICALLY = false; + } + + public static class Profile { + + /** + * If true, cook-async agent will enable profile when user create a new profile task. Otherwise disable + * profile. + */ + public static boolean ACTIVE = true; + + /** + * Parallel monitor segment count + */ + public static int MAX_PARALLEL = 5; + + /** + * Max monitor segment time(minutes), if current segment monitor time out of limit, then stop it. + */ + public static int MAX_DURATION = 10; + + /** + * Max dump thread stack depth + */ + public static int DUMP_MAX_STACK_DEPTH = 500; + + /** + * Snapshot transport to backend buffer size + */ + public static int SNAPSHOT_TRANSPORT_BUFFER_SIZE = 500; + } + + public static class Meter { + + /** + * If true, cook-async agent will enable sending meters. Otherwise disable meter report. + */ + public static boolean ACTIVE = true; + + /** + * Report meters interval + */ + public static Integer REPORT_INTERVAL = 20; + + /** + * Max size of the meter count. + */ + public static Integer MAX_METER_SIZE = 500; + } + + public static class Jvm { + + /** + * The buffer size of collected JVM info. + */ + public static int BUFFER_SIZE = 60 * 10; + } + + public static class Log { + + /** + * The max size of message to send to server.Default is 10 MB. + */ + public static int MAX_MESSAGE_SIZE = 10 * 1024 * 1024; + } + + public static class Buffer { + + public static int CHANNEL_SIZE = 5; + + public static int BUFFER_SIZE = 300; + } + + public static class Logging { + + /** + * Log file name. + */ + public static String FILE_NAME = "cook-async-api.log"; + + /** + * Log files directory. Default is blank string, means, use "{thecook-asyncAgentJarDir}/logs " to output logs. + * {thecook-asyncAgentJarDir} is the directory where the cook-async agent jar file is located. + *

+ * Ref to {@link WriterFactory#getLogWriter()} + */ + public static String DIR = ""; + + /** + * The max size of log file. If the size is bigger than this, archive the current file, and write into a new + * file. + */ + public static int MAX_FILE_SIZE = 300 * 1024 * 1024; + + /** + * The max history log files. When rollover happened, if log files exceed this number, then the oldest file will + * be delete. Negative or zero means off, by default. + */ + public static int MAX_HISTORY_FILES = -1; + + /** + * The log level. Default is debug. + */ + public static LogLevel LEVEL = LogLevel.DEBUG; + + /** + * The log output. Default is FILE. + */ + public static LogOutput OUTPUT = LogOutput.FILE; + + /** + * The log resolver type. Default is PATTERN which will create PatternLogResolver later. + */ + public static ResolverType RESOLVER = ResolverType.PATTERN; + + /** + * The log patten. Default is "%level %timestamp %thread %class : %msg %throwable". Each conversion specifiers + * starts with a percent sign '%' and fis followed by conversion word. There are some default conversion + * specifiers: %thread = ThreadName %level = LogLevel {@link LogLevel} %timestamp = The now() who format is + * 'yyyy-MM-dd HH:mm:ss:SSS' %class = SimpleName of TargetClass %msg = Message of user input %throwable = + * Throwable of user input %agent_name = ServiceName of Agent {@link Agent#SERVICE_NAME} + * + * @see com.example.agent.core.logging.core.PatternLogger#DEFAULT_CONVERTER_MAP + */ + public static String PATTERN = "%level %timestamp %thread %class : %msg %throwable"; + } + + public static class StatusCheck { + + /** + * Listed exceptions would not be treated as an error. Because in some codes, the exception is being used as a + * way of controlling business flow. + */ + public static String IGNORED_EXCEPTIONS = ""; + + /** + * The max recursive depth when checking the exception traced by the agent. Typically, we don't recommend + * setting this more than 10, which could cause a performance issue. Negative value and 0 would be ignored, + * which means all exceptions would make the span tagged in error status. + */ + public static Integer MAX_RECURSIVE_DEPTH = 1; + } + + public static class Plugin { + + /** + * Control the length of the peer field. + */ + public static int PEER_MAX_LENGTH = 200; + + /** + * Exclude activated plugins + */ + public static String EXCLUDE_PLUGINS = ""; + + /** + * Mount the folders of the plugins. The folder path is relative to agent.jar. + */ + public static List MOUNT = Arrays.asList("plugins", "activations"); + + public static class ThreadPool { + + public static List EXCLUDE_PACKAGE_PREFIX = Arrays.asList( + "java", "sun", "okhttp3", "retrofit2", "reactor", + "org.apache", "io.netty", "org.springframework", "com.ctrip", "com.google", + "io.undertow", "org.xnio", "org.jboss", "com.zaxxer", "org.redisson", "com.alibaba", + "com.netflix", "com.mysql", "rx.internal", "io.shardingjdbc", "org.drools", "org.elasticsearch", + "ch.qos.logback", "net.sf.ehcache"); + } + + public static class Apollo { + + public static class App { + + public static String ID; + } + public static String META; + + public static class BootStrap { + + public static boolean ENABLED = false; + + public static List NAMESPACES; + } + } + } + + public static class Correlation { + + /** + * Max element count in the correlation context. + */ + public static int ELEMENT_MAX_NUMBER = 3; + + /** + * Max value length of each element. + */ + public static int VALUE_MAX_LENGTH = 128; + + /** + * Tag the span by the key/value in the correlation context, when the keys listed here exist. + */ + public static String AUTO_TAG_KEYS = ""; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/ConfigNotFoundException.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/ConfigNotFoundException.java new file mode 100644 index 00000000..5bfadb10 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/ConfigNotFoundException.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.conf; + +public class ConfigNotFoundException extends Exception { + + public ConfigNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + public ConfigNotFoundException(String message) { + super(message); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/Constants.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/Constants.java new file mode 100644 index 00000000..fc1dcb39 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/Constants.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.conf; + +public class Constants { + + public static String PATH_SEPARATOR = System.getProperty("file.separator", "/"); + + public static String LINE_SEPARATOR = System.getProperty("line.separator", "\n"); + + public static String EMPTY_STRING = ""; + + public static char SERVICE_NAME_PART_CONNECTOR = '|'; + + // The name of the layer that represents agent-installed services, + // which is defined at + // https://github.com/apache/skywalking/blob/85ce1645be53e46286f36c0ea206c60db2d1a716/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Layer.java#L30 + public static String EVENT_LAYER_NAME = "GENERAL"; + + public static int NULL_VALUE = 0; + + public static String SPRING_BOOT_CONFIG_PREFIX = "spring.dynamic.thread-pool"; + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/RuntimeContextConfiguration.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/RuntimeContextConfiguration.java new file mode 100644 index 00000000..d19202fb --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/RuntimeContextConfiguration.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.conf; + +public class RuntimeContextConfiguration { + + public static String[] NEED_PROPAGATE_CONTEXT_KEY = new String[]{ + "SW_REQUEST", + "SW_RESPONSE", + "SW_WEBFLUX_REQUEST_KEY" + }; +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/SnifferConfigInitializer.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/SnifferConfigInitializer.java new file mode 100644 index 00000000..77f2d088 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/SnifferConfigInitializer.java @@ -0,0 +1,236 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.conf; + + +import com.example.agent.core.boot.AgentPackageNotFoundException; +import com.example.agent.core.boot.AgentPackagePath; +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.logging.core.JsonLogResolver; +import com.example.agent.core.logging.core.PatternLogResolver; +import com.example.agent.core.util.ConfigInitializer; +import com.example.agent.core.util.PropertyPlaceholderHelper; +import com.example.agent.core.util.StringUtil; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import static com.example.agent.core.conf.Constants.SERVICE_NAME_PART_CONNECTOR; + + +/** + * The SnifferConfigInitializer initializes all configs in several way. + */ +public class SnifferConfigInitializer { + + private static ILog LOGGER = LogManager.getLogger(SnifferConfigInitializer.class); + private static final String SPECIFIED_CONFIG_PATH = "cook-async_config"; + private static final String DEFAULT_CONFIG_FILE_NAME = "/config/agent.config"; + private static final String ENV_KEY_PREFIX = "cook-async."; + private static Properties AGENT_SETTINGS; + private static boolean IS_INIT_COMPLETED = false; + + /** + * If the specified agent config path is set, the agent will try to locate the specified agent config. If the + * specified agent config path is not set , the agent will try to locate `agent.config`, which should be in the + * /config directory of agent package. + *

+ * Also try to override the config by system.properties. All the keys in this place should start with {@link + * #ENV_KEY_PREFIX}. e.g. in env `cook-async.agent.service_name=yourAppName` to override `agent.service_name` in + * config file. + *

+ * At the end, `agent.service_name` and `collector.servers` must not be blank. + */ + public static void initializeCoreConfig(String agentOptions) { + AGENT_SETTINGS = new Properties(); + try (final InputStreamReader configFileStream = loadConfig()) { + AGENT_SETTINGS.load(configFileStream); + for (String key : AGENT_SETTINGS.stringPropertyNames()) { + String value = (String) AGENT_SETTINGS.get(key); + AGENT_SETTINGS.put(key, PropertyPlaceholderHelper.INSTANCE.replacePlaceholders(value, AGENT_SETTINGS)); + } + + } catch (Exception e) { + LOGGER.error(e, "Failed to read the config file, cook-async is going to run in default config."); + } + + try { + overrideConfigBySystemProp(); + } catch (Exception e) { + LOGGER.error(e, "Failed to read the system properties."); + } + + agentOptions = StringUtil.trim(agentOptions, ','); + if (!StringUtil.isEmpty(agentOptions)) { + try { + agentOptions = agentOptions.trim(); + LOGGER.info("Agent options is {}.", agentOptions); + + overrideConfigByAgentOptions(agentOptions); + } catch (Exception e) { + LOGGER.error(e, "Failed to parse the agent options, val is {}.", agentOptions); + } + } + + initializeConfig(Config.class); + // reconfigure logger after config initialization + configureLogger(); + LOGGER = LogManager.getLogger(SnifferConfigInitializer.class); + + if (StringUtil.isEmpty(Config.Agent.SERVICE_NAME)) { + throw new ExceptionInInitializerError("`agent.service_name` is missing."); + } else { + if (StringUtil.isNotEmpty(Config.Agent.NAMESPACE) || StringUtil.isNotEmpty(Config.Agent.CLUSTER)) { + Config.Agent.SERVICE_NAME = StringUtil.join( + SERVICE_NAME_PART_CONNECTOR, + Config.Agent.SERVICE_NAME, + Config.Agent.NAMESPACE, + Config.Agent.CLUSTER); + } + } + // if (StringUtil.isEmpty(Config.Collector.BACKEND_SERVICE)) { + // throw new ExceptionInInitializerError("`collector.backend_service` is missing."); + // } + if (Config.Plugin.PEER_MAX_LENGTH <= 3) { + LOGGER.warn( + "PEER_MAX_LENGTH configuration:{} error, the default value of 200 will be used.", + Config.Plugin.PEER_MAX_LENGTH); + Config.Plugin.PEER_MAX_LENGTH = 200; + } + + IS_INIT_COMPLETED = true; + } + + /** + * Initialize field values of any given config class. + * + * @param configClass to host the settings for code access. + */ + public static void initializeConfig(Class configClass) { + if (AGENT_SETTINGS == null) { + LOGGER.error("Plugin configs have to be initialized after core config initialization."); + return; + } + try { + ConfigInitializer.initialize(AGENT_SETTINGS, configClass); + } catch (IllegalAccessException e) { + LOGGER.error(e, + "Failed to set the agent settings {}" + + " to Config={} ", + AGENT_SETTINGS, configClass); + } + } + + private static void overrideConfigByAgentOptions(String agentOptions) throws IllegalArgumentException { + for (List terms : parseAgentOptions(agentOptions)) { + if (terms.size() != 2) { + throw new IllegalArgumentException("[" + terms + "] is not a key-value pair."); + } + AGENT_SETTINGS.put(terms.get(0), terms.get(1)); + } + } + + private static List> parseAgentOptions(String agentOptions) { + List> options = new ArrayList<>(); + List terms = new ArrayList<>(); + boolean isInQuotes = false; + StringBuilder currentTerm = new StringBuilder(); + for (char c : agentOptions.toCharArray()) { + if (c == '\'' || c == '"') { + isInQuotes = !isInQuotes; + } else if (c == '=' && !isInQuotes) { // key-value pair uses '=' as separator + terms.add(currentTerm.toString()); + currentTerm = new StringBuilder(); + } else if (c == ',' && !isInQuotes) { // multiple options use ',' as separator + terms.add(currentTerm.toString()); + currentTerm = new StringBuilder(); + + options.add(terms); + terms = new ArrayList<>(); + } else { + currentTerm.append(c); + } + } + // add the last term and option without separator + terms.add(currentTerm.toString()); + options.add(terms); + return options; + } + + public static boolean isInitCompleted() { + return IS_INIT_COMPLETED; + } + + /** + * Override the config by system properties. The property key must start with `cook-async`, the result should be as + * same as in `agent.config` + *

+ * such as: Property key of `agent.service_name` should be `cook-async.agent.service_name` + */ + private static void overrideConfigBySystemProp() { + Properties systemProperties = System.getProperties(); + for (final Map.Entry prop : systemProperties.entrySet()) { + String key = prop.getKey().toString(); + if (key.startsWith(ENV_KEY_PREFIX)) { + String realKey = key.substring(ENV_KEY_PREFIX.length()); + AGENT_SETTINGS.put(realKey, prop.getValue()); + } + } + } + + /** + * Load the specified config file or default config file + * + * + */ + private static InputStreamReader loadConfig() throws AgentPackageNotFoundException, ConfigNotFoundException { + String specifiedConfigPath = System.getProperty(SPECIFIED_CONFIG_PATH); + File configFile = StringUtil.isEmpty(specifiedConfigPath) ? new File( + AgentPackagePath.getPath(), DEFAULT_CONFIG_FILE_NAME) : new File(specifiedConfigPath); + + if (configFile.exists() && configFile.isFile()) { + try { + LOGGER.info("Config file found in {}.", configFile); + + return new InputStreamReader(new FileInputStream(configFile), StandardCharsets.UTF_8); + } catch (FileNotFoundException e) { + throw new ConfigNotFoundException("Failed to load agent.config", e); + } + } + throw new ConfigNotFoundException("Failed to load agent.config."); + } + + static void configureLogger() { + switch (Config.Logging.RESOLVER) { + case JSON: + LogManager.setLogResolver(new JsonLogResolver()); + break; + case PATTERN: + default: + LogManager.setLogResolver(new PatternLogResolver()); + } + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/dynamic/AgentConfigChangeWatcher.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/dynamic/AgentConfigChangeWatcher.java new file mode 100644 index 00000000..f857994b --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/conf/dynamic/AgentConfigChangeWatcher.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.conf.dynamic; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +public abstract class AgentConfigChangeWatcher { + + // Config key, should match KEY in the Table of Agent Configuration Properties. + private final String propertyKey; + + public AgentConfigChangeWatcher(String propertyKey) { + this.propertyKey = propertyKey; + } + + /** + * Notify the watcher, the new value received. + * + * @param value of new. + */ + public abstract void notify(ConfigChangeEvent value); + + /** + * @return current value of current config. + */ + public abstract String value(); + + @Override + public String toString() { + return "AgentConfigChangeWatcher{" + + "propertyKey='" + propertyKey + '\'' + + '}'; + } + + @Getter + @RequiredArgsConstructor + public static class ConfigChangeEvent { + + private final String newValue; + private final EventType eventType; + } + + public enum EventType { + ADD, MODIFY, DELETE + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/jvm/LoadedLibraryCollector.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/jvm/LoadedLibraryCollector.java new file mode 100644 index 00000000..34b5811f --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/jvm/LoadedLibraryCollector.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.jvm; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.util.CollectionUtil; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import java.io.File; +import java.lang.management.ManagementFactory; +import java.net.URL; +import java.net.URLClassLoader; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class LoadedLibraryCollector { + + private static final ILog LOGGER = LogManager.getLogger(LoadedLibraryCollector.class); + private static final String JAR_SEPARATOR = "!"; + private static Set CURRENT_URL_CLASSLOADER_SET = new HashSet<>(); + private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create(); + /** + * Prevent OOM in special scenes + */ + private static int CURRENT_URL_CLASSLOADER_SET_MAX_SIZE = 50; + + public static void registerURLClassLoader(ClassLoader classLoader) { + if (CURRENT_URL_CLASSLOADER_SET.size() < CURRENT_URL_CLASSLOADER_SET_MAX_SIZE && classLoader instanceof URLClassLoader) { + CURRENT_URL_CLASSLOADER_SET.add(classLoader); + } + } + + private static String getVmStartTime() { + long startTime = ManagementFactory.getRuntimeMXBean().getStartTime(); + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(startTime)); + } + + private static List getVmArgs() { + List vmArgs = ManagementFactory.getRuntimeMXBean().getInputArguments(); + List sortedVmArgs = new ArrayList<>(vmArgs); + Collections.sort(sortedVmArgs); + return sortedVmArgs; + } + + private static List getLibJarNames() { + List classLoaderUrls = loadClassLoaderUrls(); + return extractLibJarNamesFromURLs(classLoaderUrls); + } + + private static List loadClassLoaderUrls() { + List classLoaderUrls = new ArrayList<>(); + for (ClassLoader classLoader : CURRENT_URL_CLASSLOADER_SET) { + try { + URLClassLoader webappClassLoader = (URLClassLoader) classLoader; + URL[] urls = webappClassLoader.getURLs(); + classLoaderUrls.addAll(Arrays.asList(urls)); + } catch (Exception e) { + LOGGER.warn("Load classloader urls exception: {}", e.getMessage()); + } + } + return classLoaderUrls; + } + + private static List extractLibJarNamesFromURLs(List urls) { + Set libJarNames = new HashSet<>(); + for (URL url : urls) { + try { + String libJarName = extractLibJarName(url); + if (libJarName.endsWith(".jar")) { + libJarNames.add(libJarName); + } + } catch (Exception e) { + LOGGER.warn("Extracting library name exception: {}", e.getMessage()); + } + } + List sortedLibJarNames = new ArrayList<>(libJarNames.size()); + if (!CollectionUtil.isEmpty(libJarNames)) { + sortedLibJarNames.addAll(libJarNames); + Collections.sort(sortedLibJarNames); + } + return sortedLibJarNames; + } + + private static String extractLibJarName(URL url) { + String protocol = url.getProtocol(); + if (protocol.equals("file")) { + return extractNameFromFile(url.toString()); + } else if (protocol.equals("jar")) { + return extractNameFromJar(url.toString()); + } else { + return ""; + } + } + + private static String extractNameFromFile(String fileUri) { + int lastIndexOfSeparator = fileUri.lastIndexOf(File.separator); + if (lastIndexOfSeparator < 0) { + return fileUri; + } else { + return fileUri.substring(lastIndexOfSeparator + 1); + } + } + + private static String extractNameFromJar(String jarUri) { + String uri = jarUri.substring(0, jarUri.lastIndexOf(JAR_SEPARATOR)); + return extractNameFromFile(uri); + } + +} \ No newline at end of file diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/api/ILog.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/api/ILog.java new file mode 100644 index 00000000..c9325183 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/api/ILog.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.api; + +/** + * The Log interface. It's very easy to understand, like any other log-component. Do just like log4j or log4j2 does. + *

+ */ +public interface ILog { + + void info(String format); + + void info(String format, Object... arguments); + + void info(Throwable t, String format, Object... arguments); + + void warn(String format, Object... arguments); + + void warn(Throwable e, String format, Object... arguments); + + void error(String format, Throwable e); + + void error(Throwable e, String format, Object... arguments); + + boolean isDebugEnable(); + + boolean isInfoEnable(); + + boolean isWarnEnable(); + + boolean isErrorEnable(); + + boolean isTraceEnabled(); + + void debug(String format); + + void debug(String format, Object... arguments); + + void debug(Throwable t, String format, Object... arguments); + + void error(String format); + + void trace(String format); + + void trace(String format, Object... arguments); + + void trace(Throwable t, String format, Object... arguments); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/api/LogManager.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/api/LogManager.java new file mode 100644 index 00000000..8bb0fe6d --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/api/LogManager.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.api; + + +import com.example.agent.core.logging.core.PatternLogResolver; + +/** + * LogManager is the {@link LogResolver} implementation manager. By using {@link LogResolver}, {@link + * LogManager#getLogger(Class)} returns a {@link ILog} implementation. This module use this class as the main entrance, + * and block the implementation detail about log-component. In different modules, like server or sniffer, it will use + * different implementations. + * + *

If no {@link LogResolver} is registered, return {@link NoopLogger#INSTANCE} to avoid + * {@link NullPointerException}. If {@link LogManager#setLogResolver(LogResolver)} is called twice, the second will + * override the first without any warning or exception. + * + *

Created by xin on 2016/11/10. + */ +public class LogManager { + + private static LogResolver RESOLVER = new PatternLogResolver(); + + public static void setLogResolver(LogResolver resolver) { + LogManager.RESOLVER = resolver; + } + + public static ILog getLogger(Class clazz) { + if (RESOLVER == null) { + return NoopLogger.INSTANCE; + } + return LogManager.RESOLVER.getLogger(clazz); + } + + public static ILog getLogger(String clazz) { + if (RESOLVER == null) { + return NoopLogger.INSTANCE; + } + return LogManager.RESOLVER.getLogger(clazz); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/api/LogResolver.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/api/LogResolver.java new file mode 100644 index 00000000..3c28a0ad --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/api/LogResolver.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.api; + +/** + * {@link LogResolver} just do only one thing: return the {@link ILog} implementation. + *

+ */ +public interface LogResolver { + + /** + * @param clazz the class is showed in log message. + * @return {@link ILog} implementation. + */ + ILog getLogger(Class clazz); + + /** + * @param clazz the class is showed in log message. + * @return {@link ILog} implementation. + */ + ILog getLogger(String clazz); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/api/NoopLogger.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/api/NoopLogger.java new file mode 100644 index 00000000..8325329f --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/api/NoopLogger.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.api; + +/** + * No operation logger implementation. Just implement {@link ILog} interface, but do nothing. + *

+ */ +public enum NoopLogger implements ILog { + + INSTANCE; + + @Override + public void info(String message) { + + } + + @Override + public void info(String format, Object... arguments) { + + } + + @Override + public void info(final Throwable t, final String format, final Object... arguments) { + + } + + @Override + public void warn(String format, Object... arguments) { + + } + + @Override + public void error(String format, Throwable e) { + + } + + @Override + public boolean isDebugEnable() { + return false; + } + + @Override + public boolean isInfoEnable() { + return false; + } + + @Override + public boolean isWarnEnable() { + return false; + } + + @Override + public boolean isErrorEnable() { + return false; + } + + @Override + public boolean isTraceEnabled() { + return false; + } + + @Override + public void debug(String format) { + + } + + @Override + public void debug(String format, Object... arguments) { + + } + + @Override + public void debug(final Throwable t, final String format, final Object... arguments) { + + } + + @Override + public void error(String format) { + + } + + @Override + public void trace(final String format) { + + } + + @Override + public void trace(final String format, final Object... arguments) { + + } + + @Override + public void trace(final Throwable t, final String format, final Object... arguments) { + + } + + @Override + public void error(Throwable e, String format, Object... arguments) { + + } + + @Override + public void warn(Throwable e, String format, Object... arguments) { + + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/AbstractLogger.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/AbstractLogger.java new file mode 100644 index 00000000..9e19c36c --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/AbstractLogger.java @@ -0,0 +1,223 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core; + + +import com.example.agent.core.conf.Config; +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.core.converters.AgentNameConverter; +import com.example.agent.core.logging.core.converters.ClassConverter; +import com.example.agent.core.logging.core.converters.DateConverter; +import com.example.agent.core.logging.core.converters.LevelConverter; +import com.example.agent.core.logging.core.converters.MessageConverter; +import com.example.agent.core.logging.core.converters.ThreadConverter; +import com.example.agent.core.logging.core.converters.ThrowableConverter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; + +/** + * An abstract class to simplify the real implementation of the loggers. + * It hold the class name of the logger, and is responsible for log level check, + * message interpolation, etc. + */ +public abstract class AbstractLogger implements ILog { + + public static final Map> DEFAULT_CONVERTER_MAP = new HashMap<>(); + protected List converters = new ArrayList<>(); + + static { + DEFAULT_CONVERTER_MAP.put("thread", ThreadConverter.class); + DEFAULT_CONVERTER_MAP.put("level", LevelConverter.class); + DEFAULT_CONVERTER_MAP.put("agent_name", AgentNameConverter.class); + DEFAULT_CONVERTER_MAP.put("timestamp", DateConverter.class); + DEFAULT_CONVERTER_MAP.put("msg", MessageConverter.class); + DEFAULT_CONVERTER_MAP.put("throwable", ThrowableConverter.class); + DEFAULT_CONVERTER_MAP.put("class", ClassConverter.class); + } + + protected final String targetClass; + + public AbstractLogger(String targetClass) { + this.targetClass = targetClass; + } + + @Override + public void info(String message) { + if (this.isInfoEnable()) { + this.logger(LogLevel.INFO, message, null); + } + } + + @Override + public void info(String message, Object... objects) { + if (this.isInfoEnable()) { + this.logger(LogLevel.INFO, replaceParam(message, objects), null); + } + } + + @Override + public void info(final Throwable throwable, final String message, final Object... objects) { + if (this.isInfoEnable()) { + this.logger(LogLevel.INFO, replaceParam(message, objects), throwable); + } + } + + @Override + public void warn(String message, Object... objects) { + if (this.isWarnEnable()) { + this.logger(LogLevel.WARN, replaceParam(message, objects), null); + } + } + + @Override + public void warn(Throwable throwable, String message, Object... objects) { + if (this.isWarnEnable()) { + this.logger(LogLevel.WARN, replaceParam(message, objects), throwable); + } + } + + @Override + public void error(String message, Throwable throwable) { + if (this.isErrorEnable()) { + this.logger(LogLevel.ERROR, message, throwable); + } + } + + @Override + public void error(Throwable throwable, String message, Object... objects) { + if (this.isErrorEnable()) { + this.logger(LogLevel.ERROR, replaceParam(message, objects), throwable); + } + } + + @Override + public void error(String message) { + if (this.isErrorEnable()) { + this.logger(LogLevel.ERROR, message, null); + } + } + + @Override + public void debug(String message) { + if (this.isDebugEnable()) { + this.logger(LogLevel.DEBUG, message, null); + } + } + + @Override + public void debug(String message, Object... objects) { + if (this.isDebugEnable()) { + this.logger(LogLevel.DEBUG, replaceParam(message, objects), null); + } + } + + @Override + public void debug(Throwable throwable, String message, Object... objects) { + if (this.isDebugEnable()) { + this.logger(LogLevel.DEBUG, replaceParam(message, objects), throwable); + } + } + + @Override + public boolean isDebugEnable() { + return LogLevel.DEBUG.compareTo(Config.Logging.LEVEL) >= 0; + } + + @Override + public boolean isInfoEnable() { + return LogLevel.INFO.compareTo(Config.Logging.LEVEL) >= 0; + } + + @Override + public boolean isWarnEnable() { + return LogLevel.WARN.compareTo(Config.Logging.LEVEL) >= 0; + } + + @Override + public boolean isErrorEnable() { + return LogLevel.ERROR.compareTo(Config.Logging.LEVEL) >= 0; + } + + @Override + public boolean isTraceEnabled() { + return LogLevel.TRACE.compareTo(Config.Logging.LEVEL) >= 0; + } + + @Override + public void trace(final String message) { + if (this.isTraceEnabled()) { + this.logger(LogLevel.TRACE, message, null); + } + } + + @Override + public void trace(final String message, final Object... objects) { + if (this.isTraceEnabled()) { + this.logger(LogLevel.TRACE, replaceParam(message, objects), null); + } + } + + @Override + public void trace(final Throwable throwable, final String message, final Object... objects) { + if (this.isTraceEnabled()) { + this.logger(LogLevel.TRACE, replaceParam(message, objects), throwable); + } + } + + protected String replaceParam(String message, Object... parameters) { + if (message == null) { + return message; + } + int startSize = 0; + int parametersIndex = 0; + int index; + String tmpMessage = message; + while ((index = message.indexOf("{}", startSize)) != -1) { + if (parametersIndex >= parameters.length) { + break; + } + /** + * @Fix the Illegal group reference issue + */ + tmpMessage = tmpMessage.replaceFirst("\\{\\}", Matcher.quoteReplacement(String.valueOf(parameters[parametersIndex++]))); + startSize = index + 2; + } + return tmpMessage; + } + + protected void logger(LogLevel level, String message, Throwable e) { + WriterFactory.getLogWriter().write(this.format(level, message, e)); + } + + /** + * The abstract method left for real loggers. + * Any implementation MUST return string, which will be directly transferred to log destination, + * i.e. log files OR stdout + * + * @param level log level + * @param message log message, which has been interpolated with user-defined parameters. + * @param e throwable if exists + * @return string representation of the log, for example, raw json string for {@link JsonLogger} + */ + protected abstract String format(LogLevel level, String message, Throwable e); + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/Converter.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/Converter.java new file mode 100644 index 00000000..aa7453d7 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/Converter.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core; + +/** + * The Converter, it is used to convert the LogEvent to the String. + * For JsonLogger, the `getKey()` method is used to generate the key for json. + */ +public interface Converter { + + String convert(LogEvent logEvent); + + String getKey(); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/FileWriter.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/FileWriter.java new file mode 100644 index 00000000..9ecad3cd --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/FileWriter.java @@ -0,0 +1,234 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core; + +import com.example.agent.core.boot.DefaultNamedThreadFactory; +import com.example.agent.core.conf.Config; +import com.example.agent.core.conf.Constants; +import com.example.agent.core.util.RunnableWithExceptionProtection; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Date; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; + +/** + * The FileWriter support async file output, by using a queue as buffer. + */ +public class FileWriter implements IWriter { + + private static FileWriter INSTANCE; + private static final Object CREATE_LOCK = new Object(); + private FileOutputStream fileOutputStream; + private ArrayBlockingQueue logBuffer; + private volatile int fileSize; + private Pattern filenamePattern = Pattern.compile(Config.Logging.FILE_NAME + "\\.\\d{4}_\\d{2}_\\d{2}_\\d{2}_\\d{2}_\\d{2}"); + + public static FileWriter get() { + if (INSTANCE == null) { + synchronized (CREATE_LOCK) { + if (INSTANCE == null) { + INSTANCE = new FileWriter(); + } + } + } + return INSTANCE; + } + + private FileWriter() { + logBuffer = new ArrayBlockingQueue(1024); + final ArrayList outputLogs = new ArrayList(200); + Executors.newSingleThreadScheduledExecutor(new DefaultNamedThreadFactory("LogFileWriter")) + .scheduleAtFixedRate(new RunnableWithExceptionProtection(new Runnable() { + + @Override + public void run() { + try { + logBuffer.drainTo(outputLogs); + for (String log : outputLogs) { + writeToFile(log + Constants.LINE_SEPARATOR); + } + try { + if (fileOutputStream != null) { + fileOutputStream.flush(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } finally { + outputLogs.clear(); + } + } + }, new RunnableWithExceptionProtection.CallbackWhenException() { + + @Override + public void handle(Throwable t) { + } + }), 0, 1, TimeUnit.SECONDS); + } + + /** + * @param message to be written into the file. + */ + private void writeToFile(String message) { + if (prepareWriteStream()) { + try { + fileOutputStream.write(message.getBytes()); + fileSize += message.length(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + switchFile(); + } + } + } + + private void switchFile() { + if (fileSize > Config.Logging.MAX_FILE_SIZE) { + forceExecute(new Callable() { + + @Override + public Object call() throws Exception { + fileOutputStream.flush(); + return null; + } + }); + forceExecute(new Callable() { + + @Override + public Object call() throws Exception { + fileOutputStream.close(); + return null; + } + }); + forceExecute(new Callable() { + + @Override + public Object call() throws Exception { + new File(Config.Logging.DIR, Config.Logging.FILE_NAME).renameTo(new File(Config.Logging.DIR, Config.Logging.FILE_NAME + new SimpleDateFormat(".yyyy_MM_dd_HH_mm_ss") + .format(new Date()))); + return null; + } + }); + forceExecute(new Callable() { + + @Override + public Object call() throws Exception { + fileOutputStream = null; + return null; + } + }); + + if (Config.Logging.MAX_HISTORY_FILES > 0) { + deleteExpiredFiles(); + } + } + } + + /** + * load history log file name array + * + * @return history log file name array + */ + private String[] getHistoryFilePath() { + File path = new File(Config.Logging.DIR); + String[] pathArr = path.list(new FilenameFilter() { + + @Override + public boolean accept(File dir, String name) { + return filenamePattern.matcher(name).matches(); + } + }); + + return pathArr; + } + + /** + * delete expired log files + */ + private void deleteExpiredFiles() { + String[] historyFileArr = getHistoryFilePath(); + if (historyFileArr != null && historyFileArr.length > Config.Logging.MAX_HISTORY_FILES) { + + Arrays.sort(historyFileArr, new Comparator() { + + @Override + public int compare(String o1, String o2) { + return o2.compareTo(o1); + } + }); + + for (int i = Config.Logging.MAX_HISTORY_FILES; i < historyFileArr.length; i++) { + File expiredFile = new File(Config.Logging.DIR, historyFileArr[i]); + expiredFile.delete(); + } + } + } + + private void forceExecute(Callable callable) { + try { + callable.call(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * @return true if stream is prepared ready. + */ + private boolean prepareWriteStream() { + if (fileOutputStream != null) { + return true; + } + File logFilePath = new File(Config.Logging.DIR); + if (!logFilePath.exists()) { + logFilePath.mkdirs(); + } else if (!logFilePath.isDirectory()) { + System.err.println("Log dir(" + Config.Logging.DIR + ") is not a directory."); + } + try { + fileOutputStream = new FileOutputStream(new File(logFilePath, Config.Logging.FILE_NAME), true); + fileSize = Long.valueOf(new File(logFilePath, Config.Logging.FILE_NAME).length()).intValue(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + return fileOutputStream != null; + } + + /** + * Write log to the queue. W/ performance trade off. + * + * @param message to log + */ + @Override + public void write(String message) { + logBuffer.offer(message); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/IWriter.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/IWriter.java new file mode 100644 index 00000000..42a07373 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/IWriter.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core; + +public interface IWriter { + + void write(String message); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/JsonLogResolver.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/JsonLogResolver.java new file mode 100644 index 00000000..c825b9fb --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/JsonLogResolver.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core; + + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogResolver; +import com.google.gson.Gson; + +public class JsonLogResolver implements LogResolver { + + private static final Gson GSON = new Gson(); + + @Override + public ILog getLogger(Class aClass) { + return new JsonLogger(aClass, GSON); + } + + @Override + public ILog getLogger(String s) { + return new JsonLogger(s, GSON); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/JsonLogger.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/JsonLogger.java new file mode 100644 index 00000000..7ee4a9f9 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/JsonLogger.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core; + +import com.example.agent.core.logging.core.converters.LiteralConverter; +import com.google.gson.Gson; + +import java.util.HashMap; +import java.util.Map; + +/** + * An alternative logger for the cook-async agent. The default layout is + * { + * "@timestamp": "", // timestamp + * "logger": "", // name of the Logger + * "level": "", // info|debug|warn|error + * "thread": "", // thread where the log method is called + * "message": "", // your log message + * "throwable": "", + * "agent_name" "service_name" + * } + */ +public class JsonLogger extends AbstractLogger { + + private final Gson gson; + + public JsonLogger(Class targetClass, Gson gson) { + this(targetClass.getSimpleName(), gson); + } + + /** + * In the Constructor, the instances of converters are created, + * except those {@link LiteralConverter} since this class is used + * only the literals in {@link PatternLogger} , + * and thus should not be added to the json log. + * + * @param targetClass the logger class + * @param gson instance of Gson works as json serializer + */ + public JsonLogger(String targetClass, Gson gson) { + super(targetClass); + this.gson = gson; + for (Map.Entry> entry : DEFAULT_CONVERTER_MAP.entrySet()) { + final Class converterClass = entry.getValue(); + try { + if (converters instanceof LiteralConverter) { + continue; + } + converters.add(converterClass.newInstance()); + } catch (IllegalAccessException | InstantiationException e) { + throw new IllegalStateException("Create Converter error. Class: " + converterClass, e); + } + } + } + + @Override + protected String format(LogLevel level, String message, Throwable e) { + LogEvent logEvent = new LogEvent(level, message, e, this.targetClass); + Map log = new HashMap<>(this.converters.size()); + for (Converter converter : this.converters) { + log.put(converter.getKey(), converter.convert(logEvent)); + } + return this.gson.toJson(log); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/LogEvent.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/LogEvent.java new file mode 100644 index 00000000..7fe3dce4 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/LogEvent.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core; + +/** + * The representation of logging events. This instance is pass around to the List of Converter. + */ +public class LogEvent { + + public LogEvent(LogLevel level, String message, Throwable throwable, String targetClass) { + this.level = level; + this.message = message; + this.throwable = throwable; + this.targetClass = targetClass; + } + + private LogLevel level; + private String message; + private Throwable throwable; + private String targetClass; + + public String getTargetClass() { + return targetClass; + } + + public void setTargetClass(String targetClass) { + this.targetClass = targetClass; + } + + public LogLevel getLevel() { + return level; + } + + public void setLevel(LogLevel level) { + this.level = level; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Throwable getThrowable() { + return throwable; + } + + public void setThrowable(Throwable throwable) { + this.throwable = throwable; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/LogLevel.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/LogLevel.java new file mode 100644 index 00000000..79283924 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/LogLevel.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core; + +public enum LogLevel { + TRACE, DEBUG, INFO, WARN, ERROR, OFF +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/LogMessageHolder.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/LogMessageHolder.java new file mode 100644 index 00000000..61d3bc31 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/LogMessageHolder.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core; + +/** + * The LogMessageHolder is a {@link String} holder, in order to in-process propagation String across the + * disruptor queue. + */ +public class LogMessageHolder { + + private String message; + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/LogOutput.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/LogOutput.java new file mode 100644 index 00000000..8e731822 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/LogOutput.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core; + +public enum LogOutput { + FILE, CONSOLE +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/Parser.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/Parser.java new file mode 100644 index 00000000..0ca7ed7a --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/Parser.java @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core; + +import com.example.agent.core.logging.core.converters.LiteralConverter; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Parser of LogPattern. It is used to parse a pattern to the List of Converter. + */ +public class Parser { + + private final Map> convertMaps; + + enum State { + LITERAL_STATE, KEYWORD_STATE + } + + public static final char ESCAPE_CHAR = '\\'; + public static final char PERCENT_CHAR = '%'; + + private final String pattern; + private final int patternLength; + private int pointer = 0; + private State state = State.LITERAL_STATE; + + public Parser(String pattern, Map> convertMaps) { + if (pattern == null || pattern.length() == 0) { + throw new IllegalArgumentException("null or empty pattern string not allowed"); + } + this.convertMaps = convertMaps; + this.pattern = pattern; + this.patternLength = pattern.length(); + } + + public List parse() { + List patternConverters = new ArrayList(); + StringBuilder buf = new StringBuilder(); + while (pointer < patternLength) { + char c = pattern.charAt(pointer); + pointer++; + switch (state) { + case LITERAL_STATE: + handleLiteralState(c, buf, patternConverters); + break; + case KEYWORD_STATE: + handleKeywordState(c, buf, patternConverters); + break; + default: + } + } + + switch (state) { + case LITERAL_STATE: + addConverter(buf, patternConverters, LiteralConverter.class); + break; + case KEYWORD_STATE: + addConverterWithKeyword(buf, patternConverters); + break; + default: + } + return combineLiteral(patternConverters); + } + + private List combineLiteral(List patternConverters) { + List converterList = new ArrayList(); + StringBuilder stringBuilder = new StringBuilder(); + for (Converter patternConverter : patternConverters) { + if (patternConverter instanceof LiteralConverter) { + stringBuilder.append(patternConverter.convert(null)); + } else { + if (stringBuilder.length() > 0) { + converterList.add(new LiteralConverter(stringBuilder.toString())); + stringBuilder.setLength(0); + } + converterList.add(patternConverter); + } + } + return converterList; + } + + private void handleKeywordState(char c, StringBuilder buf, List patternConverters) { + if (Character.isJavaIdentifierPart(c)) { + buf.append(c); + } else if (c == PERCENT_CHAR) { + addConverterWithKeyword(buf, patternConverters); + } else { + addConverterWithKeyword(buf, patternConverters); + if (c == ESCAPE_CHAR) { + escape("%", buf); + } else { + buf.append(c); + } + state = State.LITERAL_STATE; + } + } + + private void addConverterWithKeyword(StringBuilder buf, List patternConverters) { + String keyword = buf.toString(); + if (convertMaps.containsKey(keyword)) { + addConverter(buf, patternConverters, convertMaps.get(keyword)); + } else { + buf.insert(0, "%"); + addConverter(buf, patternConverters, LiteralConverter.class); + } + } + + private void handleLiteralState(char c, StringBuilder buf, List patternConverters) { + switch (c) { + case ESCAPE_CHAR: + escape("%", buf); + break; + case PERCENT_CHAR: + addConverter(buf, patternConverters, LiteralConverter.class); + state = State.KEYWORD_STATE; + break; + default: + buf.append(c); + } + + } + + private void escape(String escapeChars, StringBuilder buf) { + if (pointer < patternLength) { + char next = pattern.charAt(pointer++); + escape(escapeChars, buf, next); + } + } + + private void addConverter(StringBuilder buf, List patternConverters, Class aClass) { + if (buf.length() > 0) { + String result = buf.toString(); + if (LiteralConverter.class.equals(aClass)) { + patternConverters.add(new LiteralConverter(result)); + } else { + try { + patternConverters.add(aClass.newInstance()); + } catch (Exception e) { + throw new IllegalStateException("Create Converter error. Class: " + aClass, e); + } + } + buf.setLength(0); + } + } + + private void escape(String escapeChars, StringBuilder buf, char next) { + if (escapeChars.indexOf(next) >= 0) { + buf.append(next); + } else { + switch (next) { + case '_': + // the \_ sequence is swallowed + break; + case '\\': + buf.append(next); + break; + case 't': + buf.append('\t'); + break; + case 'r': + buf.append('\r'); + break; + case 'n': + buf.append('\n'); + break; + default: + throw new IllegalArgumentException("Illegal char " + next + ". It not allowed as escape characters."); + } + } + } + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/PatternLogResolver.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/PatternLogResolver.java new file mode 100644 index 00000000..8834d346 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/PatternLogResolver.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core; + + +import com.example.agent.core.conf.Config; +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogResolver; + +public class PatternLogResolver implements LogResolver { + + @Override + public ILog getLogger(Class clazz) { + return new PatternLogger(clazz, Config.Logging.PATTERN); + } + + @Override + public ILog getLogger(String clazz) { + return new PatternLogger(clazz, Config.Logging.PATTERN); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/PatternLogger.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/PatternLogger.java new file mode 100644 index 00000000..e9ac32f7 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/PatternLogger.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core; + + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.util.StringUtil; + +/** + * A flexible Logger configurable with pattern string. This is default implementation of {@link ILog} This can parse a + * pattern to the List of converter with Parser. We package LogEvent with message, level,timestamp ..., passing around + * to the List of converter to concat actually Log-String. + */ +public class PatternLogger extends AbstractLogger { + + public static final String DEFAULT_PATTERN = "%level %timestamp %thread %class : %msg %throwable"; + + private String pattern; + + public PatternLogger(Class targetClass, String pattern) { + this(targetClass.getSimpleName(), pattern); + } + + public PatternLogger(String targetClass, String pattern) { + super(targetClass); + this.setPattern(pattern); + } + + public String getPattern() { + return pattern; + } + + public void setPattern(String pattern) { + if (StringUtil.isEmpty(pattern)) { + pattern = DEFAULT_PATTERN; + } + this.pattern = pattern; + this.converters = new Parser(pattern, DEFAULT_CONVERTER_MAP).parse(); + } + + @Override + protected String format(LogLevel level, String message, Throwable t) { + LogEvent logEvent = new LogEvent(level, message, t, targetClass); + StringBuilder stringBuilder = new StringBuilder(); + for (Converter converter : this.converters) { + stringBuilder.append(converter.convert(logEvent)); + } + return stringBuilder.toString(); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/ResolverType.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/ResolverType.java new file mode 100644 index 00000000..94adf507 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/ResolverType.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core; + +public enum ResolverType { + JSON, PATTERN +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/SystemOutWriter.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/SystemOutWriter.java new file mode 100644 index 00000000..da408305 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/SystemOutWriter.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core; + +import java.io.PrintStream; + +public enum SystemOutWriter implements IWriter { + + INSTANCE; + + /** + * Tricky codes for avoiding style-check. Because, in here, "system.out.println" is the only choice to output logs. + */ + @Override + public void write(String message) { + PrintStream out = System.out; + out.println(message); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/WriterFactory.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/WriterFactory.java new file mode 100644 index 00000000..8624dc79 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/WriterFactory.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core; + +import com.example.agent.core.boot.AgentPackageNotFoundException; +import com.example.agent.core.boot.AgentPackagePath; +import com.example.agent.core.conf.Config; +import com.example.agent.core.conf.SnifferConfigInitializer; +import com.example.agent.core.plugin.PluginFinder; +import com.example.agent.core.util.StringUtil; + +public class WriterFactory { + + private static IWriter WRITER; + + public static IWriter getLogWriter() { + + switch (Config.Logging.OUTPUT) { + case FILE: + if (WRITER != null) { + return WRITER; + } + if (SnifferConfigInitializer.isInitCompleted() + && PluginFinder.isPluginInitCompleted() + && AgentPackagePath.isPathFound()) { + if (StringUtil.isEmpty(Config.Logging.DIR)) { + try { + Config.Logging.DIR = AgentPackagePath.getPath() + "/logs"; + } catch (AgentPackageNotFoundException e) { + e.printStackTrace(); + } + } + WRITER = FileWriter.get(); + } else { + return SystemOutWriter.INSTANCE; + } + break; + default: + return SystemOutWriter.INSTANCE; + + } + return WRITER; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/AgentNameConverter.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/AgentNameConverter.java new file mode 100644 index 00000000..f811107e --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/AgentNameConverter.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core.converters; + + +import com.example.agent.core.conf.Config; +import com.example.agent.core.logging.core.Converter; +import com.example.agent.core.logging.core.LogEvent; + +public class AgentNameConverter implements Converter { + + @Override + public String convert(LogEvent logEvent) { + return Config.Agent.SERVICE_NAME; + } + + @Override + public String getKey() { + return "agent_name"; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/ClassConverter.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/ClassConverter.java new file mode 100644 index 00000000..d02003e5 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/ClassConverter.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core.converters; + + +import com.example.agent.core.logging.core.Converter; +import com.example.agent.core.logging.core.LogEvent; + +/** + * Just return logEvent.getTargetClass(). + */ +public class ClassConverter implements Converter { + + @Override + public String convert(LogEvent logEvent) { + return logEvent.getTargetClass(); + } + + @Override + public String getKey() { + return "logger"; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/DateConverter.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/DateConverter.java new file mode 100644 index 00000000..60c75b41 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/DateConverter.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core.converters; + + +import com.example.agent.core.logging.core.Converter; +import com.example.agent.core.logging.core.LogEvent; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * The Converter is used to return a now date with format. + */ +public class DateConverter implements Converter { + + @Override + public String convert(LogEvent logEvent) { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()); + } + + @Override + public String getKey() { + return "@timestamp"; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/LevelConverter.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/LevelConverter.java new file mode 100644 index 00000000..cbdb5f60 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/LevelConverter.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core.converters; + +import com.example.agent.core.logging.core.Converter; +import com.example.agent.core.logging.core.LogEvent; + +/** + * Just return logEvent.getLevel().name() + */ +public class LevelConverter implements Converter { + + @Override + public String convert(LogEvent logEvent) { + return logEvent.getLevel().name(); + } + + @Override + public String getKey() { + return "level"; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/LiteralConverter.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/LiteralConverter.java new file mode 100644 index 00000000..17d0cc38 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/LiteralConverter.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core.converters; + + +import com.example.agent.core.logging.core.Converter; +import com.example.agent.core.logging.core.LogEvent; + +/** + * This Converter is used to return the literal. + */ +public class LiteralConverter implements Converter { + + private final String literal; + + public LiteralConverter(String literal) { + this.literal = literal; + } + + @Override + public String convert(LogEvent logEvent) { + return literal; + } + + @Override + public String getKey() { + return ""; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/MessageConverter.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/MessageConverter.java new file mode 100644 index 00000000..b3ccbfa9 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/MessageConverter.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core.converters; + + +import com.example.agent.core.logging.core.Converter; +import com.example.agent.core.logging.core.LogEvent; + +/** + * Just return the logEvent.getMessage() + */ +public class MessageConverter implements Converter { + + @Override + public String convert(LogEvent logEvent) { + return logEvent.getMessage(); + } + + @Override + public String getKey() { + return "message"; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/ThreadConverter.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/ThreadConverter.java new file mode 100644 index 00000000..b9c021ff --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/ThreadConverter.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core.converters; + + +import com.example.agent.core.logging.core.Converter; +import com.example.agent.core.logging.core.LogEvent; + +/** + * Just return the Thread.currentThread().getName() + */ +public class ThreadConverter implements Converter { + + @Override + public String convert(LogEvent logEvent) { + return Thread.currentThread().getName(); + } + + @Override + public String getKey() { + return "thread"; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/ThrowableConverter.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/ThrowableConverter.java new file mode 100644 index 00000000..97240210 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/logging/core/converters/ThrowableConverter.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.logging.core.converters; + + +import com.example.agent.core.conf.Constants; +import com.example.agent.core.logging.core.Converter; +import com.example.agent.core.logging.core.LogEvent; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * Return the StackTrace of String with logEvent.getThrowable() + */ +public class ThrowableConverter implements Converter { + + @Override + public String convert(LogEvent logEvent) { + Throwable t = logEvent.getThrowable(); + return t == null ? "" : format(t); + } + + public static String format(Throwable t) { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + t.printStackTrace(new java.io.PrintWriter(buf, true)); + String expMessage = buf.toString(); + try { + buf.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return Constants.LINE_SEPARATOR + expMessage; + } + + @Override + public String getKey() { + return "throwable"; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/os/OSUtil.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/os/OSUtil.java new file mode 100644 index 00000000..351ad370 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/os/OSUtil.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.os; + +import java.lang.management.ManagementFactory; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Enumeration; +import java.util.LinkedList; +import java.util.List; + +public class OSUtil { + + private static volatile String OS_NAME; + private static volatile String HOST_NAME; + private static volatile List IPV4_LIST; + private static volatile int PROCESS_NO = 0; + + public static String getOsName() { + if (OS_NAME == null) { + OS_NAME = System.getProperty("os.name"); + } + return OS_NAME; + } + + public static String getHostName() { + if (HOST_NAME == null) { + try { + InetAddress host = InetAddress.getLocalHost(); + HOST_NAME = host.getHostName(); + } catch (UnknownHostException e) { + HOST_NAME = "unknown"; + } + } + return HOST_NAME; + } + + public static List getAllIPV4() { + if (IPV4_LIST == null) { + IPV4_LIST = new LinkedList<>(); + try { + Enumeration interfs = NetworkInterface.getNetworkInterfaces(); + while (interfs.hasMoreElements()) { + NetworkInterface networkInterface = interfs.nextElement(); + Enumeration inetAddresses = networkInterface.getInetAddresses(); + while (inetAddresses.hasMoreElements()) { + InetAddress address = inetAddresses.nextElement(); + if (address instanceof Inet4Address) { + String addressStr = address.getHostAddress(); + if ("127.0.0.1".equals(addressStr)) { + continue; + } else if ("localhost".equals(addressStr)) { + continue; + } + IPV4_LIST.add(addressStr); + } + } + } + } catch (SocketException e) { + + } + } + return IPV4_LIST; + } + + public static String getIPV4() { + final List allIPV4 = getAllIPV4(); + if (allIPV4.size() > 0) { + return allIPV4.get(0); + } else { + return "no-hostname"; + } + } + + public static int getProcessNo() { + if (PROCESS_NO == 0) { + try { + PROCESS_NO = Integer.parseInt(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]); + } catch (Exception e) { + PROCESS_NO = -1; + } + } + return PROCESS_NO; + } + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/os/ProcessorUtil.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/os/ProcessorUtil.java new file mode 100644 index 00000000..0847d2a7 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/os/ProcessorUtil.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.os; + +import java.lang.management.ManagementFactory; + +public class ProcessorUtil { + + public static int getNumberOfProcessors() { + return ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors(); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/AbstractClassEnhancePluginDefine.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/AbstractClassEnhancePluginDefine.java new file mode 100644 index 00000000..fe3c97fd --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/AbstractClassEnhancePluginDefine.java @@ -0,0 +1,202 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import com.example.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import com.example.agent.core.plugin.interceptor.StaticMethodsInterceptPoint; +import com.example.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine; +import com.example.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point; +import com.example.agent.core.plugin.interceptor.v2.StaticMethodsInterceptV2Point; +import com.example.agent.core.plugin.match.ClassMatch; +import com.example.agent.core.util.CollectionUtil; +import com.example.agent.core.util.StringUtil; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.DynamicType; + +import java.util.List; + +/** + * Basic abstract class of all sky-walking auto-instrumentation plugins. + *

+ * It provides the outline of enhancing the target class. If you want to know more about enhancing, you should go to see + * {@link ClassEnhancePluginDefine} + */ +public abstract class AbstractClassEnhancePluginDefine { + + private static final ILog LOGGER = LogManager.getLogger(AbstractClassEnhancePluginDefine.class); + + /** + * New field name. + */ + public static final String CONTEXT_ATTR_NAME = "_$EnhancedClassField_ws"; + + /** + * Main entrance of enhancing the class. + * + * @param typeDescription target class description. + * @param builder byte-buddy's builder to manipulate target class's bytecode. + * @param classLoader load the given transformClass + * @return the new builder, or null if not be enhanced. + * @throws PluginException when set builder failure. + */ + public DynamicType.Builder define(TypeDescription typeDescription, DynamicType.Builder builder, + ClassLoader classLoader, EnhanceContext context) throws PluginException { + String interceptorDefineClassName = this.getClass().getName(); + String transformClassName = typeDescription.getTypeName(); + if (StringUtil.isEmpty(transformClassName)) { + LOGGER.warn("classname of being intercepted is not defined by {}.", interceptorDefineClassName); + return null; + } + + LOGGER.debug("prepare to enhance class {} by {}.", transformClassName, interceptorDefineClassName); + WitnessFinder finder = WitnessFinder.INSTANCE; + /** + * find witness classes for enhance class + */ + String[] witnessClasses = witnessClasses(); + if (witnessClasses != null) { + for (String witnessClass : witnessClasses) { + if (!finder.exist(witnessClass, classLoader)) { + LOGGER.warn("enhance class {} by plugin {} is not activated. Witness class {} does not exist.", transformClassName, interceptorDefineClassName, witnessClass); + return null; + } + } + } + List witnessMethods = witnessMethods(); + if (!CollectionUtil.isEmpty(witnessMethods)) { + for (WitnessMethod witnessMethod : witnessMethods) { + if (!finder.exist(witnessMethod, classLoader)) { + LOGGER.warn("enhance class {} by plugin {} is not activated. Witness method {} does not exist.", transformClassName, interceptorDefineClassName, witnessMethod); + return null; + } + } + } + + /** + * find origin class source code for interceptor + */ + DynamicType.Builder newClassBuilder = this.enhance(typeDescription, builder, classLoader, context); + + context.initializationStageCompleted(); + LOGGER.debug("enhance class {} by {} completely.", transformClassName, interceptorDefineClassName); + + return newClassBuilder; + } + + /** + * Begin to define how to enhance class. After invoke this method, only means definition is finished. + * + * @param typeDescription target class description + * @param newClassBuilder byte-buddy's builder to manipulate class bytecode. + * @return new byte-buddy's builder for further manipulation. + */ + protected DynamicType.Builder enhance(TypeDescription typeDescription, DynamicType.Builder newClassBuilder, + ClassLoader classLoader, EnhanceContext context) throws PluginException { + newClassBuilder = this.enhanceClass(typeDescription, newClassBuilder, classLoader); + + newClassBuilder = this.enhanceInstance(typeDescription, newClassBuilder, classLoader, context); + + return newClassBuilder; + } + + /** + * Enhance a class to intercept constructors and class instance methods. + * + * @param typeDescription target class description + * @param newClassBuilder byte-buddy's builder to manipulate class bytecode. + * @return new byte-buddy's builder for further manipulation. + */ + protected abstract DynamicType.Builder enhanceInstance(TypeDescription typeDescription, + DynamicType.Builder newClassBuilder, ClassLoader classLoader, + EnhanceContext context) throws PluginException; + + /** + * Enhance a class to intercept class static methods. + * + * @param typeDescription target class description + * @param newClassBuilder byte-buddy's builder to manipulate class bytecode. + * @return new byte-buddy's builder for further manipulation. + */ + protected abstract DynamicType.Builder enhanceClass(TypeDescription typeDescription, DynamicType.Builder newClassBuilder, + ClassLoader classLoader) throws PluginException; + + /** + * Define the {@link ClassMatch} for filtering class. + * + * @return {@link ClassMatch} + */ + protected abstract ClassMatch enhanceClass(); + + /** + * Witness classname list. Why need witness classname? Let's see like this: A library existed two released versions + * (like 1.0, 2.0), which include the same target classes, but because of version iterator, they may have the same + * name, but different methods, or different method arguments list. So, if I want to target the particular version + * (let's say 1.0 for example), version number is obvious not an option, this is the moment you need "Witness + * classes". You can add any classes only in this particular release version ( something like class + * com.company.1.x.A, only in 1.0 ), and you can achieve the goal. + */ + protected String[] witnessClasses() { + return new String[]{}; + } + + protected List witnessMethods() { + return null; + } + + public boolean isBootstrapInstrumentation() { + return false; + } + + /** + * Constructor methods intercept point. See {@link ConstructorInterceptPoint} + * + * @return collections of {@link ConstructorInterceptPoint} + */ + public abstract ConstructorInterceptPoint[] getConstructorsInterceptPoints(); + + /** + * Instance methods intercept point. See {@link InstanceMethodsInterceptPoint} + * + * @return collections of {@link InstanceMethodsInterceptPoint} + */ + public abstract InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints(); + + /** + * Instance methods intercept v2 point. See {@link InstanceMethodsInterceptV2Point} + * + * @return collections of {@link InstanceMethodsInterceptV2Point} + */ + public abstract InstanceMethodsInterceptV2Point[] getInstanceMethodsInterceptV2Points(); + + /** + * Static methods intercept point. See {@link StaticMethodsInterceptPoint} + * + * @return collections of {@link StaticMethodsInterceptPoint} + */ + public abstract StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints(); + + /** + * Instance methods intercept v2 point. See {@link InstanceMethodsInterceptV2Point} + * + * @return collections of {@link InstanceMethodsInterceptV2Point} + */ + public abstract StaticMethodsInterceptV2Point[] getStaticMethodsInterceptV2Points(); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/ByteBuddyCoreClasses.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/ByteBuddyCoreClasses.java new file mode 100644 index 00000000..5b4a5c83 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/ByteBuddyCoreClasses.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin; + +/** + * All ByteBuddy core classes required to expose, including open edge for JDK 9+ module, or Bootstrap instrumentation. + */ +public class ByteBuddyCoreClasses { + + private static final String SHADE_PACKAGE = "com.example.agent.dependencies."; + + public static final String[] CLASSES = { + SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.RuntimeType", + SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.This", + SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.AllArguments", + SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.AllArguments$Assignment", + SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.SuperCall", + SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.Origin", + SHADE_PACKAGE + "net.bytebuddy.implementation.bind.annotation.Morph", + }; +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/DynamicPluginLoader.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/DynamicPluginLoader.java new file mode 100644 index 00000000..29e2a992 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/DynamicPluginLoader.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin; + +import com.example.agent.core.plugin.loader.AgentClassLoader; +import com.example.agent.core.plugin.loader.InstrumentationLoader; + +import java.util.ArrayList; +import java.util.List; +import java.util.ServiceLoader; + +/** + * The plugin can be inserted into the kernel by implementing this spi return PluginDefine list. + */ + +public enum DynamicPluginLoader { + + INSTANCE; + + public List load(AgentClassLoader classLoader) { + List all = new ArrayList(); + for (InstrumentationLoader instrumentationLoader : ServiceLoader.load(InstrumentationLoader.class, classLoader)) { + List plugins = instrumentationLoader.load(classLoader); + if (plugins != null && !plugins.isEmpty()) { + all.addAll(plugins); + } + } + return all; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/EnhanceContext.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/EnhanceContext.java new file mode 100644 index 00000000..9c84fc1d --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/EnhanceContext.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin; + +import com.example.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine; + +/** + * The EnhanceContext represents the context or status for processing a class. + *

+ * Based on this context, the plugin core {@link ClassEnhancePluginDefine} knows how to process the specific steps for + * every particular plugin. + */ +public class EnhanceContext { + + private boolean isEnhanced = false; + /** + * The object has already been enhanced or extended. e.g. added the new field, or implemented the new interface + */ + private boolean objectExtended = false; + + public boolean isEnhanced() { + return isEnhanced; + } + + public void initializationStageCompleted() { + isEnhanced = true; + } + + public boolean isObjectExtended() { + return objectExtended; + } + + public void extendObjectCompleted() { + objectExtended = true; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/InstrumentDebuggingClass.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/InstrumentDebuggingClass.java new file mode 100644 index 00000000..5e5dd1c0 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/InstrumentDebuggingClass.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin; + +import com.example.agent.core.boot.AgentPackageNotFoundException; +import com.example.agent.core.boot.AgentPackagePath; +import com.example.agent.core.conf.Config; +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import net.bytebuddy.dynamic.DynamicType; + +import java.io.File; +import java.io.IOException; + +/** + * The manipulated class output. Write the dynamic classes to the `debugging` folder, when we need to do some debug and + * recheck. + */ +public enum InstrumentDebuggingClass { + + INSTANCE; + + private static final ILog LOGGER = LogManager.getLogger(InstrumentDebuggingClass.class); + private File debuggingClassesRootPath; + + public void log(DynamicType dynamicType) { + if (!Config.Agent.IS_OPEN_DEBUGGING_CLASS) { + return; + } + + /** + * try to do I/O things in synchronized way, to avoid unexpected situations. + */ + synchronized (INSTANCE) { + try { + if (debuggingClassesRootPath == null) { + try { + debuggingClassesRootPath = new File(AgentPackagePath.getPath(), "/debugging"); + if (!debuggingClassesRootPath.exists()) { + debuggingClassesRootPath.mkdir(); + } + } catch (AgentPackageNotFoundException e) { + LOGGER.error(e, "Can't find the root path for creating /debugging folder."); + } + } + + try { + dynamicType.saveIn(debuggingClassesRootPath); + } catch (IOException e) { + LOGGER.error(e, "Can't save class {} to file." + dynamicType.getTypeDescription().getActualName()); + } + } catch (Throwable t) { + LOGGER.error(t, "Save debugging classes fail."); + } + } + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginBootstrap.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginBootstrap.java new file mode 100644 index 00000000..e4f3be14 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginBootstrap.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin; + +import com.example.agent.core.boot.AgentPackageNotFoundException; +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.loader.AgentClassLoader; + +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +/** + * Plugins finder. Use {@link PluginResourcesResolver} to find all plugins, and ask {@link PluginCfg} to load all plugin + * definitions. + */ +public class PluginBootstrap { + + private static final ILog LOGGER = LogManager.getLogger(PluginBootstrap.class); + + /** + * load all plugins. + * + * @return plugin definition list. + */ + public List loadPlugins() throws AgentPackageNotFoundException { + AgentClassLoader.initDefaultLoader(); + + PluginResourcesResolver resolver = new PluginResourcesResolver(); + List resources = resolver.getResources(); + + if (resources == null || resources.size() == 0) { + LOGGER.info("no plugin files (cook-async-plugin.def) found, continue to start application."); + return new ArrayList(); + } + + for (URL pluginUrl : resources) { + try { + PluginCfg.INSTANCE.load(pluginUrl.openStream()); + } catch (Throwable t) { + LOGGER.error(t, "plugin file [{}] init failure.", pluginUrl); + } + } + + List pluginClassList = PluginCfg.INSTANCE.getPluginClassList(); + + List plugins = new ArrayList(); + for (PluginDefine pluginDefine : pluginClassList) { + try { + LOGGER.debug("loading plugin class {}.", pluginDefine.getDefineClass()); + AbstractClassEnhancePluginDefine plugin = (AbstractClassEnhancePluginDefine) Class.forName(pluginDefine.getDefineClass(), true, AgentClassLoader + .getDefault()).newInstance(); + plugins.add(plugin); + } catch (Throwable t) { + LOGGER.error(t, "load plugin [{}] failure.", pluginDefine.getDefineClass()); + } + } + + plugins.addAll(DynamicPluginLoader.INSTANCE.load(AgentClassLoader.getDefault())); + + return plugins; + + } + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginCfg.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginCfg.java new file mode 100644 index 00000000..7b769014 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginCfg.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.exception.IllegalPluginDefineException; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + +public enum PluginCfg { + + INSTANCE; + + private static final ILog LOGGER = LogManager.getLogger(PluginCfg.class); + + private List pluginClassList = new ArrayList(); + private PluginSelector pluginSelector = new PluginSelector(); + + void load(InputStream input) throws IOException { + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(input)); + String pluginDefine; + while ((pluginDefine = reader.readLine()) != null) { + try { + if (pluginDefine.trim().length() == 0 || pluginDefine.startsWith("#")) { + continue; + } + PluginDefine plugin = PluginDefine.build(pluginDefine); + pluginClassList.add(plugin); + } catch (IllegalPluginDefineException e) { + LOGGER.error(e, "Failed to format plugin({}) define.", pluginDefine); + } + } + pluginClassList = pluginSelector.select(pluginClassList); + } finally { + input.close(); + } + } + + public List getPluginClassList() { + return pluginClassList; + } + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginDefine.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginDefine.java new file mode 100644 index 00000000..d2b0bf1f --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginDefine.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin; + +import com.example.agent.core.plugin.exception.IllegalPluginDefineException; +import com.example.agent.core.util.StringUtil; + +public class PluginDefine { + + /** + * Plugin name. + */ + private String name; + + /** + * The class name of plugin defined. + */ + private String defineClass; + + private PluginDefine(String name, String defineClass) { + this.name = name; + this.defineClass = defineClass; + } + + public static PluginDefine build(String define) throws IllegalPluginDefineException { + if (StringUtil.isEmpty(define)) { + throw new IllegalPluginDefineException(define); + } + + String[] pluginDefine = define.split("="); + if (pluginDefine.length != 2) { + throw new IllegalPluginDefineException(define); + } + + String pluginName = pluginDefine[0]; + String defineClass = pluginDefine[1]; + return new PluginDefine(pluginName, defineClass); + } + + public String getDefineClass() { + return defineClass; + } + + public String getName() { + return name; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginException.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginException.java new file mode 100644 index 00000000..5f11a20d --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginException.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin; + +public class PluginException extends RuntimeException { + + private static final long serialVersionUID = -6020188711867490724L; + + public PluginException(String message) { + super(message); + } + + public PluginException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginFinder.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginFinder.java new file mode 100644 index 00000000..2954671a --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginFinder.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin; + +import com.example.agent.core.plugin.bytebuddy.AbstractJunction; +import com.example.agent.core.plugin.match.ClassMatch; +import com.example.agent.core.plugin.match.IndirectMatch; +import com.example.agent.core.plugin.match.NameMatch; +import com.example.agent.core.plugin.match.ProtectiveShieldMatcher; +import net.bytebuddy.description.NamedElement; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import static net.bytebuddy.matcher.ElementMatchers.isInterface; +import static net.bytebuddy.matcher.ElementMatchers.not; + +/** + * The PluginFinder represents a finder , which assist to find the one from the given {@link + * AbstractClassEnhancePluginDefine} list. + */ +public class PluginFinder { + + private final Map> nameMatchDefine = new HashMap>(); + private final List signatureMatchDefine = new ArrayList(); + private final List bootstrapClassMatchDefine = new ArrayList(); + private static boolean IS_PLUGIN_INIT_COMPLETED = false; + + public PluginFinder(List plugins) { + for (AbstractClassEnhancePluginDefine plugin : plugins) { + ClassMatch match = plugin.enhanceClass(); + + if (match == null) { + continue; + } + + if (match instanceof NameMatch) { + NameMatch nameMatch = (NameMatch) match; + LinkedList pluginDefines = nameMatchDefine.get(nameMatch.getClassName()); + if (pluginDefines == null) { + pluginDefines = new LinkedList(); + nameMatchDefine.put(nameMatch.getClassName(), pluginDefines); + } + pluginDefines.add(plugin); + } else { + signatureMatchDefine.add(plugin); + } + + if (plugin.isBootstrapInstrumentation()) { + bootstrapClassMatchDefine.add(plugin); + } + } + } + + public List find(TypeDescription typeDescription) { + List matchedPlugins = new LinkedList(); + String typeName = typeDescription.getTypeName(); + if (nameMatchDefine.containsKey(typeName)) { + matchedPlugins.addAll(nameMatchDefine.get(typeName)); + } + + for (AbstractClassEnhancePluginDefine pluginDefine : signatureMatchDefine) { + IndirectMatch match = (IndirectMatch) pluginDefine.enhanceClass(); + if (match.isMatch(typeDescription)) { + matchedPlugins.add(pluginDefine); + } + } + + return matchedPlugins; + } + + public ElementMatcher buildMatch() { + ElementMatcher.Junction judge = new AbstractJunction() { + + @Override + public boolean matches(NamedElement target) { + return nameMatchDefine.containsKey(target.getActualName()); + } + }; + judge = judge.and(not(isInterface())); + for (AbstractClassEnhancePluginDefine define : signatureMatchDefine) { + ClassMatch match = define.enhanceClass(); + if (match instanceof IndirectMatch) { + judge = judge.or(((IndirectMatch) match).buildJunction()); + } + } + return new ProtectiveShieldMatcher(judge); + } + + public List getBootstrapClassMatchDefine() { + return bootstrapClassMatchDefine; + } + + public static void pluginInitCompleted() { + IS_PLUGIN_INIT_COMPLETED = true; + } + + public static boolean isPluginInitCompleted() { + return IS_PLUGIN_INIT_COMPLETED; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginResourcesResolver.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginResourcesResolver.java new file mode 100644 index 00000000..e9475546 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginResourcesResolver.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.loader.AgentClassLoader; + +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +/** + * Use the current classloader to read all plugin define file. The file must be named 'cook-async-plugin.def' + */ +public class PluginResourcesResolver { + + private static final ILog LOGGER = LogManager.getLogger(PluginResourcesResolver.class); + + public List getResources() { + List cfgUrlPaths = new ArrayList(); + Enumeration urls; + try { + urls = AgentClassLoader.getDefault().getResources("cook-plugin.def"); + + while (urls.hasMoreElements()) { + URL pluginUrl = urls.nextElement(); + cfgUrlPaths.add(pluginUrl); + LOGGER.info("find cook-async plugin define in {}", pluginUrl); + } + + return cfgUrlPaths; + } catch (IOException e) { + LOGGER.error("read resources failure.", e); + } + return null; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginSelector.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginSelector.java new file mode 100644 index 00000000..7b88f1e8 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/PluginSelector.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin; + +import com.example.agent.core.conf.Config; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import static com.example.agent.core.conf.Config.Plugin.EXCLUDE_PLUGINS; + +/** + * Select some plugins in activated plugins + */ +public class PluginSelector { + + /** + * Exclude activated plugins + * + * @param pluginDefines the pluginDefines is loaded from activations directory or plugins directory + * @return real activate plugins + * @see Config.Plugin#EXCLUDE_PLUGINS + */ + public List select(List pluginDefines) { + if (!EXCLUDE_PLUGINS.isEmpty()) { + List excludes = Arrays.asList(EXCLUDE_PLUGINS.toLowerCase().split(",")); + return pluginDefines.stream() + .filter(item -> !excludes.contains(item.getName().toLowerCase())) + .collect(Collectors.toList()); + } + return pluginDefines; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/WitnessFinder.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/WitnessFinder.java new file mode 100644 index 00000000..f30dbb0c --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/WitnessFinder.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin; + +import net.bytebuddy.pool.TypePool; + +import java.util.HashMap; +import java.util.Map; + +/** + * The WitnessFinder represents a pool of {@link TypePool}s, each {@link TypePool} matches a {@link + * ClassLoader}, which helps to find the class declaration existed or not. + */ +public enum WitnessFinder { + + INSTANCE; + + private final Map poolMap = new HashMap(); + + /** + * @param classLoader for finding the witnessClass + * @return true, if the given witnessClass exists, through the given classLoader. + */ + public boolean exist(String witnessClass, ClassLoader classLoader) { + return getResolution(witnessClass, classLoader) + .isResolved(); + } + + /** + * get TypePool.Resolution of the witness class + * @param witnessClass class name + * @param classLoader classLoader for finding the witnessClass + * @return TypePool.Resolution + */ + private TypePool.Resolution getResolution(String witnessClass, ClassLoader classLoader) { + ClassLoader mappingKey = classLoader == null ? NullClassLoader.INSTANCE : classLoader; + if (!poolMap.containsKey(mappingKey)) { + synchronized (poolMap) { + if (!poolMap.containsKey(mappingKey)) { + TypePool classTypePool = classLoader == null ? TypePool.Default.ofBootLoader() : TypePool.Default.of(classLoader); + poolMap.put(mappingKey, classTypePool); + } + } + } + TypePool typePool = poolMap.get(mappingKey); + return typePool.describe(witnessClass); + } + + /** + * @param classLoader for finding the witness method + * @return true, if the given witness method exists, through the given classLoader. + */ + public boolean exist(WitnessMethod witnessMethod, ClassLoader classLoader) { + TypePool.Resolution resolution = getResolution(witnessMethod.getDeclaringClassName(), classLoader); + if (!resolution.isResolved()) { + return false; + } + return !resolution.resolve() + .getDeclaredMethods() + .filter(witnessMethod.getElementMatcher()) + .isEmpty(); + } + +} + +final class NullClassLoader extends ClassLoader { + + static NullClassLoader INSTANCE = new NullClassLoader(); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/WitnessMethod.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/WitnessMethod.java new file mode 100644 index 00000000..4f5d28da --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/WitnessMethod.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * Witness Method for plugin activation + */ +@ToString +@RequiredArgsConstructor +public class WitnessMethod { + + /** + * the class or interface name where the witness method is declared. + */ + @Getter + private final String declaringClassName; + /** + * matcher to match the witness method + */ + @Getter + private final ElementMatcher elementMatcher; + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/BootstrapInstrumentBoost.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/BootstrapInstrumentBoost.java new file mode 100644 index 00000000..59d25c50 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/BootstrapInstrumentBoost.java @@ -0,0 +1,301 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bootstrap; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.AbstractClassEnhancePluginDefine; +import com.example.agent.core.plugin.ByteBuddyCoreClasses; +import com.example.agent.core.plugin.InstrumentDebuggingClass; +import com.example.agent.core.plugin.PluginException; +import com.example.agent.core.plugin.PluginFinder; +import com.example.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import com.example.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import com.example.agent.core.plugin.interceptor.StaticMethodsInterceptPoint; +import com.example.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point; +import com.example.agent.core.plugin.interceptor.v2.StaticMethodsInterceptV2Point; +import com.example.agent.core.plugin.jdk9module.JDK9ModuleExporter; +import com.example.agent.core.plugin.loader.AgentClassLoader; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.ClassFileLocator; +import net.bytebuddy.dynamic.DynamicType; +import net.bytebuddy.dynamic.loading.ClassInjector; +import net.bytebuddy.pool.TypePool; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.instrument.Instrumentation; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static net.bytebuddy.matcher.ElementMatchers.named; + +/** + * If there is Bootstrap instrumentation plugin declared in plugin list, BootstrapInstrumentBoost inject the necessary + * classes into bootstrap class loader, including generated dynamic delegate classes. + */ +public class BootstrapInstrumentBoost { + + private static final ILog LOGGER = LogManager.getLogger(BootstrapInstrumentBoost.class); + + private static final String[] HIGH_PRIORITY_CLASSES = { + "com.example.agent.core.plugin.interceptor.enhance.BootstrapInterRuntimeAssist", + "com.example.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor", + "com.example.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor", + "com.example.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor", + "com.example.agent.core.plugin.bootstrap.IBootstrapLog", + "com.example.agent.core.plugin.interceptor.enhance.EnhancedInstance", + "com.example.agent.core.plugin.interceptor.enhance.OverrideCallable", + "com.example.agent.core.plugin.interceptor.enhance.MethodInterceptResult", + + // interceptor v2 + "com.example.agent.core.plugin.interceptor.enhance.v2.InstanceMethodsAroundInterceptorV2", + "com.example.agent.core.plugin.interceptor.enhance.v2.StaticMethodsAroundInterceptorV2", + "com.example.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext", + }; + + private static String INSTANCE_METHOD_DELEGATE_TEMPLATE = "com.example.agent.core.plugin.bootstrap.template.InstanceMethodInterTemplate"; + private static String INSTANCE_METHOD_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE = "com.example.agent.core.plugin.bootstrap.template.InstanceMethodInterWithOverrideArgsTemplate"; + private static String CONSTRUCTOR_DELEGATE_TEMPLATE = "com.example.agent.core.plugin.bootstrap.template.ConstructorInterTemplate"; + private static String STATIC_METHOD_DELEGATE_TEMPLATE = "com.example.agent.core.plugin.bootstrap.template.StaticMethodInterTemplate"; + private static String STATIC_METHOD_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE = "com.example.agent.core.plugin.bootstrap.template.StaticMethodInterWithOverrideArgsTemplate"; + + private static String INSTANCE_METHOD_V2_DELEGATE_TEMPLATE = "com.example.agent.core.plugin.bootstrap.template.v2.InstanceMethodInterV2Template"; + private static String INSTANCE_METHOD_V2_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE = "com.example.agent.core.plugin.bootstrap.template.v2.InstanceMethodInterV2WithOverrideArgsTemplate"; + private static String STATIC_METHOD_V2_DELEGATE_TEMPLATE = "com.example.agent.core.plugin.bootstrap.template.v2.StaticMethodInterV2Template"; + private static String STATIC_METHOD_V2_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE = "com.example.agent.core.plugin.bootstrap.template.v2.StaticMethodInterV2WithOverrideArgsTemplate"; + + public static AgentBuilder inject(PluginFinder pluginFinder, Instrumentation instrumentation, + AgentBuilder agentBuilder, JDK9ModuleExporter.EdgeClasses edgeClasses) throws PluginException { + Map classesTypeMap = new LinkedHashMap<>(); + + if (!prepareJREInstrumentation(pluginFinder, classesTypeMap)) { + return agentBuilder; + } + + if (!prepareJREInstrumentationV2(pluginFinder, classesTypeMap)) { + return agentBuilder; + } + + for (String highPriorityClass : HIGH_PRIORITY_CLASSES) { + loadHighPriorityClass(classesTypeMap, highPriorityClass); + } + for (String highPriorityClass : ByteBuddyCoreClasses.CLASSES) { + loadHighPriorityClass(classesTypeMap, highPriorityClass); + } + + /** + * Prepare to open edge of necessary classes. + */ + for (String generatedClass : classesTypeMap.keySet()) { + edgeClasses.add(generatedClass); + } + + /** + * Inject the classes into bootstrap class loader by using Unsafe Strategy. + * ByteBuddy adapts the sun.misc.Unsafe and jdk.internal.misc.Unsafe automatically. + */ + ClassInjector.UsingUnsafe.Factory factory = ClassInjector.UsingUnsafe.Factory.resolve(instrumentation); + factory.make(null, null).injectRaw(classesTypeMap); + agentBuilder = agentBuilder.with(new AgentBuilder.InjectionStrategy.UsingUnsafe.OfFactory(factory)); + + return agentBuilder; + } + + /** + * Get the delegate class name. + * + * @param methodsInterceptor of original interceptor in the plugin + * @return generated delegate class name + */ + public static String internalDelegate(String methodsInterceptor) { + return methodsInterceptor + "_internal"; + } + + /** + * Load the delegate class from current class loader, mostly should be AppClassLoader. + * + * @param methodsInterceptor of original interceptor in the plugin + * @return generated delegate class + */ + public static Class forInternalDelegateClass(String methodsInterceptor) { + try { + return Class.forName(internalDelegate(methodsInterceptor)); + } catch (ClassNotFoundException e) { + throw new PluginException(e.getMessage(), e); + } + } + + /** + * Generate dynamic delegate for ByteBuddy + * + * @param pluginFinder gets the whole plugin list. + * @param classesTypeMap hosts the class binary. + * @return true if have JRE instrumentation requirement. + * @throws PluginException when generate failure. + */ + private static boolean prepareJREInstrumentation(PluginFinder pluginFinder, + Map classesTypeMap) throws PluginException { + TypePool typePool = TypePool.Default.of(BootstrapInstrumentBoost.class.getClassLoader()); + List bootstrapClassMatchDefines = pluginFinder.getBootstrapClassMatchDefine(); + for (AbstractClassEnhancePluginDefine define : bootstrapClassMatchDefines) { + if (Objects.nonNull(define.getInstanceMethodsInterceptPoints())) { + for (InstanceMethodsInterceptPoint point : define.getInstanceMethodsInterceptPoints()) { + if (point.isOverrideArgs()) { + generateDelegator( + classesTypeMap, typePool, INSTANCE_METHOD_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE, point + .getMethodsInterceptor()); + } else { + generateDelegator( + classesTypeMap, typePool, INSTANCE_METHOD_DELEGATE_TEMPLATE, point.getMethodsInterceptor()); + } + } + } + + if (Objects.nonNull(define.getConstructorsInterceptPoints())) { + for (ConstructorInterceptPoint point : define.getConstructorsInterceptPoints()) { + generateDelegator( + classesTypeMap, typePool, CONSTRUCTOR_DELEGATE_TEMPLATE, point.getConstructorInterceptor()); + } + } + + if (Objects.nonNull(define.getStaticMethodsInterceptPoints())) { + for (StaticMethodsInterceptPoint point : define.getStaticMethodsInterceptPoints()) { + if (point.isOverrideArgs()) { + generateDelegator( + classesTypeMap, typePool, STATIC_METHOD_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE, point + .getMethodsInterceptor()); + } else { + generateDelegator( + classesTypeMap, typePool, STATIC_METHOD_DELEGATE_TEMPLATE, point.getMethodsInterceptor()); + } + } + } + } + return bootstrapClassMatchDefines.size() > 0; + } + + private static boolean prepareJREInstrumentationV2(PluginFinder pluginFinder, + Map classesTypeMap) throws PluginException { + TypePool typePool = TypePool.Default.of(BootstrapInstrumentBoost.class.getClassLoader()); + List bootstrapClassMatchDefines = pluginFinder.getBootstrapClassMatchDefine(); + for (AbstractClassEnhancePluginDefine define : bootstrapClassMatchDefines) { + if (Objects.nonNull(define.getInstanceMethodsInterceptV2Points())) { + for (InstanceMethodsInterceptV2Point point : define.getInstanceMethodsInterceptV2Points()) { + if (point.isOverrideArgs()) { + generateDelegator(classesTypeMap, typePool, + INSTANCE_METHOD_V2_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE, + point.getMethodsInterceptorV2()); + } else { + generateDelegator( + classesTypeMap, typePool, INSTANCE_METHOD_V2_DELEGATE_TEMPLATE, + point.getMethodsInterceptorV2()); + } + } + } + + if (Objects.nonNull(define.getStaticMethodsInterceptV2Points())) { + for (StaticMethodsInterceptV2Point point : define.getStaticMethodsInterceptV2Points()) { + if (point.isOverrideArgs()) { + generateDelegator(classesTypeMap, typePool, + STATIC_METHOD_V2_WITH_OVERRIDE_ARGS_DELEGATE_TEMPLATE, + point.getMethodsInterceptorV2()); + } else { + generateDelegator( + classesTypeMap, typePool, STATIC_METHOD_V2_DELEGATE_TEMPLATE, + point.getMethodsInterceptorV2()); + } + } + } + } + return bootstrapClassMatchDefines.size() > 0; + } + + /** + * Generate the delegator class based on given template class. This is preparation stage level code generation. + *

+ * One key step to avoid class confliction between AppClassLoader and BootstrapClassLoader + * + * @param classesTypeMap hosts injected binary of generated class + * @param typePool to generate new class + * @param templateClassName represents the class as template in this generation process. The templates are + * pre-defined in cook-async agent core. + */ + private static void generateDelegator(Map classesTypeMap, TypePool typePool, + String templateClassName, String methodsInterceptor) { + String internalInterceptorName = internalDelegate(methodsInterceptor); + try { + TypeDescription templateTypeDescription = typePool.describe(templateClassName).resolve(); + + DynamicType.Unloaded interceptorType = new ByteBuddy().redefine(templateTypeDescription, ClassFileLocator.ForClassLoader + .of(BootstrapInstrumentBoost.class.getClassLoader())) + .name(internalInterceptorName) + .field(named("TARGET_INTERCEPTOR")) + .value(methodsInterceptor) + .make(); + + classesTypeMap.put(internalInterceptorName, interceptorType.getBytes()); + + InstrumentDebuggingClass.INSTANCE.log(interceptorType); + } catch (Exception e) { + throw new PluginException("Generate Dynamic plugin failure", e); + } + } + + /** + * The class loaded by this method means it only should be loaded once in Bootstrap classloader, when bootstrap + * instrumentation active by any plugin + * + * @param loadedTypeMap hosts all injected class + * @param className to load + */ + private static void loadHighPriorityClass(Map loadedTypeMap, + String className) throws PluginException { + byte[] enhancedInstanceClassFile; + try { + String classResourceName = className.replaceAll("\\.", "/") + ".class"; + InputStream resourceAsStream = AgentClassLoader.getDefault().getResourceAsStream(classResourceName); + + if (resourceAsStream == null) { + throw new PluginException("High priority class " + className + " not found."); + } + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + + byte[] buffer = new byte[1024]; + int len; + + // read bytes from the input stream and store them in buffer + while ((len = resourceAsStream.read(buffer)) != -1) { + // write bytes from the buffer into output stream + os.write(buffer, 0, len); + } + + enhancedInstanceClassFile = os.toByteArray(); + } catch (IOException e) { + throw new PluginException(e.getMessage(), e); + } + + loadedTypeMap.put(className, enhancedInstanceClassFile); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/BootstrapPluginLogBridge.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/BootstrapPluginLogBridge.java new file mode 100644 index 00000000..17e0c9b2 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/BootstrapPluginLogBridge.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bootstrap; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; + +/** + * The log bridge makes the ILog accessible inside bootstrap classloader, especially for internal interceptor. + */ +public class BootstrapPluginLogBridge implements IBootstrapLog { + + public static IBootstrapLog getLogger(String clazz) { + return new BootstrapPluginLogBridge(clazz); + } + + private final ILog logger; + + private BootstrapPluginLogBridge(String clazz) { + logger = LogManager.getLogger(clazz); + } + + @Override + public void info(String format) { + logger.info(format); + } + + @Override + public void info(String format, Object... arguments) { + logger.info(format, arguments); + } + + @Override + public void warn(String format, Object... arguments) { + logger.warn(format, arguments); + } + + @Override + public void warn(Throwable e, String format, Object... arguments) { + logger.warn(e, format, arguments); + } + + @Override + public void error(String format, Throwable e) { + logger.error(format, e); + } + + @Override + public void error(Throwable e, String format, Object... arguments) { + logger.error(e, format, arguments); + } + + @Override + public boolean isDebugEnable() { + return logger.isDebugEnable(); + } + + @Override + public boolean isInfoEnable() { + return logger.isInfoEnable(); + } + + @Override + public boolean isWarnEnable() { + return logger.isWarnEnable(); + } + + @Override + public boolean isErrorEnable() { + return logger.isErrorEnable(); + } + + @Override + public void debug(String format) { + logger.debug(format); + } + + @Override + public void debug(String format, Object... arguments) { + logger.debug(format, arguments); + } + + @Override + public void error(String format) { + logger.error(format); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/IBootstrapLog.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/IBootstrapLog.java new file mode 100644 index 00000000..d5dc2cfd --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/IBootstrapLog.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bootstrap; + +/** + * The log interface used in bootstrap internal interceptors. + *

+ * Never used in any plugin or tracing core. + */ +public interface IBootstrapLog { + + void info(String format); + + void info(String format, Object... arguments); + + void warn(String format, Object... arguments); + + void warn(Throwable e, String format, Object... arguments); + + void error(String format, Throwable e); + + void error(Throwable e, String format, Object... arguments); + + boolean isDebugEnable(); + + boolean isInfoEnable(); + + boolean isWarnEnable(); + + boolean isErrorEnable(); + + void debug(String format); + + void debug(String format, Object... arguments); + + void error(String format); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/ConstructorInterTemplate.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/ConstructorInterTemplate.java new file mode 100644 index 00000000..ab51fe96 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/ConstructorInterTemplate.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bootstrap.template; + +import com.example.agent.core.plugin.bootstrap.IBootstrapLog; +import com.example.agent.core.plugin.interceptor.enhance.BootstrapInterRuntimeAssist; +import com.example.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import com.example.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.This; + +public class ConstructorInterTemplate { + + /** + * This field is never set in the template, but has value in the runtime. + */ + private static String TARGET_INTERCEPTOR; + + private static InstanceConstructorInterceptor INTERCEPTOR; + private static IBootstrapLog LOGGER; + + /** + * Intercept the target constructor. + * + * @param obj target class instance. + * @param allArguments all constructor arguments + */ + @RuntimeType + public static void intercept(@This Object obj, @AllArguments Object[] allArguments) { + try { + prepare(); + + EnhancedInstance targetObject = (EnhancedInstance) obj; + + if (INTERCEPTOR == null) { + return; + } + INTERCEPTOR.onConstruct(targetObject, allArguments); + } catch (Throwable t) { + LOGGER.error("ConstructorInter failure.", t); + } + } + + /** + * Prepare the context. Link to the agent core in AppClassLoader. + */ + private static void prepare() { + if (INTERCEPTOR == null) { + ClassLoader loader = BootstrapInterRuntimeAssist.getAgentClassLoader(); + + if (loader != null) { + IBootstrapLog logger = BootstrapInterRuntimeAssist.getLogger(loader, TARGET_INTERCEPTOR); + if (logger != null) { + LOGGER = logger; + + INTERCEPTOR = BootstrapInterRuntimeAssist.createInterceptor(loader, TARGET_INTERCEPTOR, LOGGER); + } + } else { + LOGGER.error("Runtime ClassLoader not found when create {}." + TARGET_INTERCEPTOR); + } + } + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/InstanceMethodInterTemplate.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/InstanceMethodInterTemplate.java new file mode 100644 index 00000000..a2390710 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/InstanceMethodInterTemplate.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bootstrap.template; + +import com.example.agent.core.plugin.bootstrap.IBootstrapLog; +import com.example.agent.core.plugin.interceptor.enhance.BootstrapInterRuntimeAssist; +import com.example.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import com.example.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; +import com.example.agent.core.plugin.interceptor.enhance.MethodInterceptResult; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.SuperCall; +import net.bytebuddy.implementation.bind.annotation.This; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +public class InstanceMethodInterTemplate { + + /** + * This field is never set in the template, but has value in the runtime. + */ + private static String TARGET_INTERCEPTOR; + + private static InstanceMethodsAroundInterceptor INTERCEPTOR; + private static IBootstrapLog LOGGER; + + /** + * Intercept the target instance method. + * + * @param obj target class instance. + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target instance method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public static Object intercept(@This Object obj, @AllArguments Object[] allArguments, @SuperCall Callable zuper, + @Origin Method method) throws Throwable { + EnhancedInstance targetObject = (EnhancedInstance) obj; + + prepare(); + + MethodInterceptResult result = new MethodInterceptResult(); + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.beforeMethod(targetObject, method, allArguments, method.getParameterTypes(), result); + } + } catch (Throwable t) { + if (LOGGER != null) { + LOGGER.error(t, "class[{}] before method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + + Object ret = null; + try { + if (!result.isContinue()) { + ret = result._ret(); + } else { + ret = zuper.call(); + } + } catch (Throwable t) { + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.handleMethodException(targetObject, method, allArguments, method.getParameterTypes(), t); + } + } catch (Throwable t2) { + if (LOGGER != null) { + LOGGER.error(t2, "class[{}] handle method[{}] exception failure", obj.getClass(), method.getName()); + } + } + throw t; + } finally { + try { + if (INTERCEPTOR != null) { + ret = INTERCEPTOR.afterMethod(targetObject, method, allArguments, method.getParameterTypes(), ret); + } + } catch (Throwable t) { + if (LOGGER != null) { + LOGGER.error(t, "class[{}] after method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + } + + return ret; + } + + /** + * Prepare the context. Link to the agent core in AppClassLoader. + */ + private static void prepare() { + if (INTERCEPTOR == null) { + ClassLoader loader = BootstrapInterRuntimeAssist.getAgentClassLoader(); + + if (loader != null) { + IBootstrapLog logger = BootstrapInterRuntimeAssist.getLogger(loader, TARGET_INTERCEPTOR); + if (logger != null) { + LOGGER = logger; + + INTERCEPTOR = BootstrapInterRuntimeAssist.createInterceptor(loader, TARGET_INTERCEPTOR, LOGGER); + } + } else { + LOGGER.error("Runtime ClassLoader not found when create {}." + TARGET_INTERCEPTOR); + } + } + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/InstanceMethodInterWithOverrideArgsTemplate.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/InstanceMethodInterWithOverrideArgsTemplate.java new file mode 100644 index 00000000..b94bc164 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/InstanceMethodInterWithOverrideArgsTemplate.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bootstrap.template; + +import com.example.agent.core.plugin.bootstrap.IBootstrapLog; +import com.example.agent.core.plugin.interceptor.enhance.BootstrapInterRuntimeAssist; +import com.example.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import com.example.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; +import com.example.agent.core.plugin.interceptor.enhance.MethodInterceptResult; +import com.example.agent.core.plugin.interceptor.enhance.OverrideCallable; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Morph; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.This; + +import java.lang.reflect.Method; + +public class InstanceMethodInterWithOverrideArgsTemplate { + + /** + * This field is never set in the template, but has value in the runtime. + */ + private static String TARGET_INTERCEPTOR; + + private static InstanceMethodsAroundInterceptor INTERCEPTOR; + private static IBootstrapLog LOGGER; + + /** + * Intercept the target instance method. + * + * @param obj target class instance. + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target instance method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public static Object intercept(@This Object obj, @AllArguments Object[] allArguments, @Morph OverrideCallable zuper, + @Origin Method method) throws Throwable { + EnhancedInstance targetObject = (EnhancedInstance) obj; + + prepare(); + + MethodInterceptResult result = new MethodInterceptResult(); + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.beforeMethod(targetObject, method, allArguments, method.getParameterTypes(), result); + } + } catch (Throwable t) { + if (LOGGER != null) { + LOGGER.error(t, "class[{}] before method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + + Object ret = null; + try { + if (!result.isContinue()) { + ret = result._ret(); + } else { + ret = zuper.call(allArguments); + } + } catch (Throwable t) { + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.handleMethodException(targetObject, method, allArguments, method.getParameterTypes(), t); + } + } catch (Throwable t2) { + if (LOGGER != null) { + LOGGER.error(t2, "class[{}] handle method[{}] exception failure", obj.getClass(), method.getName()); + } + } + throw t; + } finally { + try { + if (INTERCEPTOR != null) { + ret = INTERCEPTOR.afterMethod(targetObject, method, allArguments, method.getParameterTypes(), ret); + } + } catch (Throwable t) { + if (LOGGER != null) { + LOGGER.error(t, "class[{}] after method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + } + + return ret; + } + + /** + * Prepare the context. Link to the agent core in AppClassLoader. + */ + private static void prepare() { + if (INTERCEPTOR == null) { + ClassLoader loader = BootstrapInterRuntimeAssist.getAgentClassLoader(); + + if (loader != null) { + IBootstrapLog logger = BootstrapInterRuntimeAssist.getLogger(loader, TARGET_INTERCEPTOR); + if (logger != null) { + LOGGER = logger; + + INTERCEPTOR = BootstrapInterRuntimeAssist.createInterceptor(loader, TARGET_INTERCEPTOR, LOGGER); + } + } else { + LOGGER.error("Runtime ClassLoader not found when create {}." + TARGET_INTERCEPTOR); + } + } + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/StaticMethodInterTemplate.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/StaticMethodInterTemplate.java new file mode 100644 index 00000000..249285e4 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/StaticMethodInterTemplate.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bootstrap.template; + +import com.example.agent.core.plugin.bootstrap.IBootstrapLog; +import com.example.agent.core.plugin.interceptor.enhance.BootstrapInterRuntimeAssist; +import com.example.agent.core.plugin.interceptor.enhance.MethodInterceptResult; +import com.example.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.SuperCall; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +public class StaticMethodInterTemplate { + + /** + * This field is never set in the template, but has value in the runtime. + */ + private static String TARGET_INTERCEPTOR; + + private static StaticMethodsAroundInterceptor INTERCEPTOR; + private static IBootstrapLog LOGGER; + + /** + * Intercept the target static method. + * + * @param clazz target class + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target static method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public static Object intercept(@Origin Class clazz, @AllArguments Object[] allArguments, @Origin Method method, + @SuperCall Callable zuper) throws Throwable { + prepare(); + + MethodInterceptResult result = new MethodInterceptResult(); + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.beforeMethod(clazz, method, allArguments, method.getParameterTypes(), result); + } + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before static method[{}] intercept failure", clazz, method.getName()); + } + + Object ret = null; + try { + if (!result.isContinue()) { + ret = result._ret(); + } else { + ret = zuper.call(); + } + } catch (Throwable t) { + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.handleMethodException(clazz, method, allArguments, method.getParameterTypes(), t); + } + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle static method[{}] exception failure", clazz, method.getName(), t2.getMessage()); + } + throw t; + } finally { + try { + if (INTERCEPTOR != null) { + ret = INTERCEPTOR.afterMethod(clazz, method, allArguments, method.getParameterTypes(), ret); + } + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after static method[{}] intercept failure:{}", clazz, method.getName(), t.getMessage()); + } + } + return ret; + } + + /** + * Prepare the context. Link to the agent core in AppClassLoader. + */ + private static void prepare() { + if (INTERCEPTOR == null) { + ClassLoader loader = BootstrapInterRuntimeAssist.getAgentClassLoader(); + + if (loader != null) { + IBootstrapLog logger = BootstrapInterRuntimeAssist.getLogger(loader, TARGET_INTERCEPTOR); + if (logger != null) { + LOGGER = logger; + + INTERCEPTOR = BootstrapInterRuntimeAssist.createInterceptor(loader, TARGET_INTERCEPTOR, LOGGER); + } + } else { + LOGGER.error("Runtime ClassLoader not found when create {}." + TARGET_INTERCEPTOR); + } + } + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/StaticMethodInterWithOverrideArgsTemplate.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/StaticMethodInterWithOverrideArgsTemplate.java new file mode 100644 index 00000000..666143cb --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/StaticMethodInterWithOverrideArgsTemplate.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bootstrap.template; + +import com.example.agent.core.plugin.bootstrap.IBootstrapLog; +import com.example.agent.core.plugin.interceptor.enhance.BootstrapInterRuntimeAssist; +import com.example.agent.core.plugin.interceptor.enhance.MethodInterceptResult; +import com.example.agent.core.plugin.interceptor.enhance.OverrideCallable; +import com.example.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Morph; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; + +import java.lang.reflect.Method; + +public class StaticMethodInterWithOverrideArgsTemplate { + + /** + * This field is never set in the template, but has value in the runtime. + */ + private static String TARGET_INTERCEPTOR; + + private static StaticMethodsAroundInterceptor INTERCEPTOR; + private static IBootstrapLog LOGGER; + + /** + * Intercept the target static method. + * + * @param clazz target class + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target static method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public static Object intercept(@Origin Class clazz, @AllArguments Object[] allArguments, @Origin Method method, + @Morph OverrideCallable zuper) throws Throwable { + prepare(); + + MethodInterceptResult result = new MethodInterceptResult(); + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.beforeMethod(clazz, method, allArguments, method.getParameterTypes(), result); + } + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before static method[{}] intercept failure", clazz, method.getName()); + } + + Object ret = null; + try { + if (!result.isContinue()) { + ret = result._ret(); + } else { + ret = zuper.call(allArguments); + } + } catch (Throwable t) { + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.handleMethodException(clazz, method, allArguments, method.getParameterTypes(), t); + } + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle static method[{}] exception failure", clazz, method.getName(), t2.getMessage()); + } + throw t; + } finally { + try { + if (INTERCEPTOR != null) { + ret = INTERCEPTOR.afterMethod(clazz, method, allArguments, method.getParameterTypes(), ret); + } + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after static method[{}] intercept failure:{}", clazz, method.getName(), t.getMessage()); + } + } + return ret; + } + + /** + * Prepare the context. Link to the agent core in AppClassLoader. + */ + private static void prepare() { + if (INTERCEPTOR == null) { + ClassLoader loader = BootstrapInterRuntimeAssist.getAgentClassLoader(); + + if (loader != null) { + IBootstrapLog logger = BootstrapInterRuntimeAssist.getLogger(loader, TARGET_INTERCEPTOR); + if (logger != null) { + LOGGER = logger; + + INTERCEPTOR = BootstrapInterRuntimeAssist.createInterceptor(loader, TARGET_INTERCEPTOR, LOGGER); + } + } else { + LOGGER.error("Runtime ClassLoader not found when create {}." + TARGET_INTERCEPTOR); + } + } + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/v2/InstanceMethodInterV2Template.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/v2/InstanceMethodInterV2Template.java new file mode 100644 index 00000000..75254fda --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/v2/InstanceMethodInterV2Template.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bootstrap.template.v2; + +import com.example.agent.core.plugin.bootstrap.IBootstrapLog; +import com.example.agent.core.plugin.interceptor.enhance.BootstrapInterRuntimeAssist; +import com.example.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import com.example.agent.core.plugin.interceptor.enhance.v2.InstanceMethodsAroundInterceptorV2; +import com.example.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.SuperCall; +import net.bytebuddy.implementation.bind.annotation.This; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +/** + * This class wouldn't be loaded in real env. This is a class template for dynamic class generation. + */ +public class InstanceMethodInterV2Template { + + /** + * This field is never set in the template, but has value in the runtime. + */ + private static String TARGET_INTERCEPTOR; + + private static InstanceMethodsAroundInterceptorV2 INTERCEPTOR; + private static IBootstrapLog LOGGER; + + /** + * Intercept the target instance method. + * + * @param obj target class instance. + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target instance method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public static Object intercept(@This Object obj, @AllArguments Object[] allArguments, @SuperCall Callable zuper, + @Origin Method method) throws Throwable { + EnhancedInstance targetObject = (EnhancedInstance) obj; + + prepare(); + + MethodInvocationContext context = new MethodInvocationContext(); + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.beforeMethod(targetObject, method, allArguments, method.getParameterTypes(), context); + } + } catch (Throwable t) { + if (LOGGER != null) { + LOGGER.error(t, "class[{}] before method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + + Object ret = null; + try { + if (!context.isContinue()) { + ret = context._ret(); + } else { + ret = zuper.call(); + } + } catch (Throwable t) { + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.handleMethodException(targetObject, method, allArguments, method.getParameterTypes(), t, context); + } + } catch (Throwable t2) { + if (LOGGER != null) { + LOGGER.error(t2, "class[{}] handle method[{}] exception failure", obj.getClass(), method.getName()); + } + } + throw t; + } finally { + try { + if (INTERCEPTOR != null) { + ret = INTERCEPTOR.afterMethod(targetObject, method, allArguments, method.getParameterTypes(), ret, context); + } + } catch (Throwable t) { + if (LOGGER != null) { + LOGGER.error(t, "class[{}] after method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + } + + return ret; + } + + /** + * Prepare the context. Link to the agent core in AppClassLoader. + */ + private static void prepare() { + if (INTERCEPTOR == null) { + ClassLoader loader = BootstrapInterRuntimeAssist.getAgentClassLoader(); + + if (loader != null) { + IBootstrapLog logger = BootstrapInterRuntimeAssist.getLogger(loader, TARGET_INTERCEPTOR); + if (logger != null) { + LOGGER = logger; + + INTERCEPTOR = BootstrapInterRuntimeAssist.createInterceptor(loader, TARGET_INTERCEPTOR, LOGGER); + } + } else { + LOGGER.error("Runtime ClassLoader not found when create {}." + TARGET_INTERCEPTOR); + } + } + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/v2/InstanceMethodInterV2WithOverrideArgsTemplate.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/v2/InstanceMethodInterV2WithOverrideArgsTemplate.java new file mode 100644 index 00000000..a87d4e66 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/v2/InstanceMethodInterV2WithOverrideArgsTemplate.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bootstrap.template.v2; + +import com.example.agent.core.plugin.bootstrap.IBootstrapLog; +import com.example.agent.core.plugin.interceptor.enhance.BootstrapInterRuntimeAssist; +import com.example.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import com.example.agent.core.plugin.interceptor.enhance.OverrideCallable; +import com.example.agent.core.plugin.interceptor.enhance.v2.InstanceMethodsAroundInterceptorV2; +import com.example.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Morph; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.This; + +import java.lang.reflect.Method; + +/** + * This class wouldn't be loaded in real env. This is a class template for dynamic class generation. + */ +public class InstanceMethodInterV2WithOverrideArgsTemplate { + + /** + * This field is never set in the template, but has value in the runtime. + */ + private static String TARGET_INTERCEPTOR; + + private static InstanceMethodsAroundInterceptorV2 INTERCEPTOR; + private static IBootstrapLog LOGGER; + + /** + * Intercept the target instance method. + * + * @param obj target class instance. + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target instance method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public static Object intercept(@This Object obj, @AllArguments Object[] allArguments, @Morph OverrideCallable zuper, + @Origin Method method) throws Throwable { + EnhancedInstance targetObject = (EnhancedInstance) obj; + + prepare(); + + MethodInvocationContext context = new MethodInvocationContext(); + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.beforeMethod(targetObject, method, allArguments, method.getParameterTypes(), context); + } + } catch (Throwable t) { + if (LOGGER != null) { + LOGGER.error(t, "class[{}] before method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + + Object ret = null; + try { + if (!context.isContinue()) { + ret = context._ret(); + } else { + ret = zuper.call(allArguments); + } + } catch (Throwable t) { + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.handleMethodException(targetObject, method, allArguments, method.getParameterTypes(), t, context); + } + } catch (Throwable t2) { + if (LOGGER != null) { + LOGGER.error(t2, "class[{}] handle method[{}] exception failure", obj.getClass(), method.getName()); + } + } + throw t; + } finally { + try { + if (INTERCEPTOR != null) { + ret = INTERCEPTOR.afterMethod(targetObject, method, allArguments, method.getParameterTypes(), ret, context); + } + } catch (Throwable t) { + if (LOGGER != null) { + LOGGER.error(t, "class[{}] after method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + } + + return ret; + } + + /** + * Prepare the context. Link to the agent core in AppClassLoader. + */ + private static void prepare() { + if (INTERCEPTOR == null) { + ClassLoader loader = BootstrapInterRuntimeAssist.getAgentClassLoader(); + + if (loader != null) { + IBootstrapLog logger = BootstrapInterRuntimeAssist.getLogger(loader, TARGET_INTERCEPTOR); + if (logger != null) { + LOGGER = logger; + + INTERCEPTOR = BootstrapInterRuntimeAssist.createInterceptor(loader, TARGET_INTERCEPTOR, LOGGER); + } + } else { + LOGGER.error("Runtime ClassLoader not found when create {}." + TARGET_INTERCEPTOR); + } + } + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/v2/StaticMethodInterV2Template.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/v2/StaticMethodInterV2Template.java new file mode 100644 index 00000000..46a439db --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/v2/StaticMethodInterV2Template.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bootstrap.template.v2; + +import com.example.agent.core.plugin.bootstrap.IBootstrapLog; +import com.example.agent.core.plugin.interceptor.enhance.BootstrapInterRuntimeAssist; +import com.example.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext; +import com.example.agent.core.plugin.interceptor.enhance.v2.StaticMethodsAroundInterceptorV2; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.SuperCall; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +/** + * This class wouldn't be loaded in real env. This is a class template for dynamic class generation. + */ +public class StaticMethodInterV2Template { + + /** + * This field is never set in the template, but has value in the runtime. + */ + private static String TARGET_INTERCEPTOR; + + private static StaticMethodsAroundInterceptorV2 INTERCEPTOR; + private static IBootstrapLog LOGGER; + + /** + * Intercept the target static method. + * + * @param clazz target class + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target static method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public static Object intercept(@Origin Class clazz, @AllArguments Object[] allArguments, @Origin Method method, + @SuperCall Callable zuper) throws Throwable { + prepare(); + + MethodInvocationContext context = new MethodInvocationContext(); + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.beforeMethod(clazz, method, allArguments, method.getParameterTypes(), context); + } + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before static method[{}] intercept failure", clazz, method.getName()); + } + + Object ret = null; + try { + if (!context.isContinue()) { + ret = context._ret(); + } else { + ret = zuper.call(); + } + } catch (Throwable t) { + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.handleMethodException(clazz, method, allArguments, method.getParameterTypes(), t, context); + } + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle static method[{}] exception failure", clazz, method.getName(), t2.getMessage()); + } + throw t; + } finally { + try { + if (INTERCEPTOR != null) { + ret = INTERCEPTOR.afterMethod(clazz, method, allArguments, method.getParameterTypes(), ret, context); + } + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after static method[{}] intercept failure:{}", clazz, method.getName(), t.getMessage()); + } + } + return ret; + } + + /** + * Prepare the context. Link to the agent core in AppClassLoader. + */ + private static void prepare() { + if (INTERCEPTOR == null) { + ClassLoader loader = BootstrapInterRuntimeAssist.getAgentClassLoader(); + + if (loader != null) { + IBootstrapLog logger = BootstrapInterRuntimeAssist.getLogger(loader, TARGET_INTERCEPTOR); + if (logger != null) { + LOGGER = logger; + + INTERCEPTOR = BootstrapInterRuntimeAssist.createInterceptor(loader, TARGET_INTERCEPTOR, LOGGER); + } + } else { + LOGGER.error("Runtime ClassLoader not found when create {}." + TARGET_INTERCEPTOR); + } + } + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/v2/StaticMethodInterV2WithOverrideArgsTemplate.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/v2/StaticMethodInterV2WithOverrideArgsTemplate.java new file mode 100644 index 00000000..52fd5a28 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bootstrap/template/v2/StaticMethodInterV2WithOverrideArgsTemplate.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bootstrap.template.v2; + +import com.example.agent.core.plugin.bootstrap.IBootstrapLog; +import com.example.agent.core.plugin.interceptor.enhance.BootstrapInterRuntimeAssist; +import com.example.agent.core.plugin.interceptor.enhance.OverrideCallable; +import com.example.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext; +import com.example.agent.core.plugin.interceptor.enhance.v2.StaticMethodsAroundInterceptorV2; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Morph; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; + +import java.lang.reflect.Method; + +/** + * This class wouldn't be loaded in real env. This is a class template for dynamic class generation. + */ +public class StaticMethodInterV2WithOverrideArgsTemplate { + + /** + * This field is never set in the template, but has value in the runtime. + */ + private static String TARGET_INTERCEPTOR; + + private static StaticMethodsAroundInterceptorV2 INTERCEPTOR; + private static IBootstrapLog LOGGER; + + /** + * Intercept the target static method. + * + * @param clazz target class + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target static method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public static Object intercept(@Origin Class clazz, @AllArguments Object[] allArguments, @Origin Method method, + @Morph OverrideCallable zuper) throws Throwable { + prepare(); + + MethodInvocationContext context = new MethodInvocationContext(); + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.beforeMethod(clazz, method, allArguments, method.getParameterTypes(), context); + } + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before static method[{}] intercept failure", clazz, method.getName()); + } + + Object ret = null; + try { + if (!context.isContinue()) { + ret = context._ret(); + } else { + ret = zuper.call(allArguments); + } + } catch (Throwable t) { + try { + if (INTERCEPTOR != null) { + INTERCEPTOR.handleMethodException(clazz, method, allArguments, method.getParameterTypes(), t, context); + } + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle static method[{}] exception failure", clazz, method.getName(), t2.getMessage()); + } + throw t; + } finally { + try { + if (INTERCEPTOR != null) { + ret = INTERCEPTOR.afterMethod(clazz, method, allArguments, method.getParameterTypes(), ret, context); + } + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after static method[{}] intercept failure:{}", clazz, method.getName(), t.getMessage()); + } + } + return ret; + } + + /** + * Prepare the context. Link to the agent core in AppClassLoader. + */ + private static void prepare() { + if (INTERCEPTOR == null) { + ClassLoader loader = BootstrapInterRuntimeAssist.getAgentClassLoader(); + + if (loader != null) { + IBootstrapLog logger = BootstrapInterRuntimeAssist.getLogger(loader, TARGET_INTERCEPTOR); + if (logger != null) { + LOGGER = logger; + + INTERCEPTOR = BootstrapInterRuntimeAssist.createInterceptor(loader, TARGET_INTERCEPTOR, LOGGER); + } + } else { + LOGGER.error("Runtime ClassLoader not found when create {}." + TARGET_INTERCEPTOR); + } + } + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/AbstractJunction.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/AbstractJunction.java new file mode 100644 index 00000000..b68a6ab9 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/AbstractJunction.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bytebuddy; + +import net.bytebuddy.matcher.ElementMatcher; + +public abstract class AbstractJunction implements ElementMatcher.Junction { + + @Override + public Junction and(ElementMatcher other) { + return new Conjunction(this, other); + } + + @Override + public Junction or(ElementMatcher other) { + return new Disjunction(this, other); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/AnnotationTypeNameMatch.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/AnnotationTypeNameMatch.java new file mode 100644 index 00000000..f325d03f --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/AnnotationTypeNameMatch.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bytebuddy; + +import net.bytebuddy.description.annotation.AnnotationDescription; +import net.bytebuddy.description.annotation.AnnotationSource; +import net.bytebuddy.matcher.CollectionItemMatcher; +import net.bytebuddy.matcher.DeclaringAnnotationMatcher; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * Annotation Type match. Similar with {@link net.bytebuddy.matcher.ElementMatchers#isAnnotatedWith}, the only different + * between them is this match use {@link String} to declare the type, instead of {@link Class}. This can avoid the + * classloader risk. + *

+ * 2019-08-15 + */ +public class AnnotationTypeNameMatch implements ElementMatcher { + + /** + * the target annotation type + */ + private String annotationTypeName; + + /** + * declare the match target method with the certain type. + * + * @param annotationTypeName target annotation type + */ + private AnnotationTypeNameMatch(String annotationTypeName) { + this.annotationTypeName = annotationTypeName; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean matches(T target) { + return target.getAnnotationType().asErasure().getName().equals(annotationTypeName); + } + + /** + * The static method to create {@link AnnotationTypeNameMatch} This is a delegate method to follow byte-buddy {@link + * ElementMatcher}'s code style. + * + * @param annotationTypeName target annotation type + * @param The type of the object that is being matched. + * @return new {@link AnnotationTypeNameMatch} instance. + */ + public static Junction isAnnotatedWithType( + String annotationTypeName) { + final AnnotationTypeNameMatch matcher = new AnnotationTypeNameMatch(annotationTypeName); + return new DeclaringAnnotationMatcher(new CollectionItemMatcher(matcher)); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/ArgumentTypeNameMatch.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/ArgumentTypeNameMatch.java new file mode 100644 index 00000000..f0b1da83 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/ArgumentTypeNameMatch.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bytebuddy; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.method.ParameterList; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * Argument Type match. Similar with {@link net.bytebuddy.matcher.ElementMatchers#takesArgument}, the only different + * between them is this match use {@link String} to declare the type, instead of {@link Class}. This can avoid the + * classloader risk. + *

+ */ +public class ArgumentTypeNameMatch implements ElementMatcher { + + /** + * the index of arguments list. + */ + private int index; + + /** + * the target argument type at {@link ArgumentTypeNameMatch#index} of the arguments list. + */ + private String argumentTypeName; + + /** + * declare the match target method with the certain index and type. + * + * @param index the index of arguments list. + * @param argumentTypeName target argument type + */ + private ArgumentTypeNameMatch(int index, String argumentTypeName) { + ArrayTypeNameChecker.check(argumentTypeName); + + this.index = index; + this.argumentTypeName = argumentTypeName; + } + + /** + * Match the target method. + * + * @param target target method description. + * @return true if matched. or false. + */ + @Override + public boolean matches(MethodDescription target) { + ParameterList parameters = target.getParameters(); + if (parameters.size() > index) { + return parameters.get(index).getType().asErasure().getName().equals(argumentTypeName); + } + + return false; + } + + /** + * The static method to create {@link ArgumentTypeNameMatch} This is a delegate method to follow byte-buddy {@link + * ElementMatcher}'s code style. + * + * @param index the index of arguments list. + * @param argumentTypeName target argument type + * @return new {@link ArgumentTypeNameMatch} instance. + */ + public static ElementMatcher takesArgumentWithType(int index, String argumentTypeName) { + return new ArgumentTypeNameMatch(index, argumentTypeName); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/ArrayTypeNameChecker.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/ArrayTypeNameChecker.java new file mode 100644 index 00000000..7f7e6c91 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/ArrayTypeNameChecker.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bytebuddy; + +public class ArrayTypeNameChecker { + + public static void check(String typeName) { + if (typeName.endsWith("[]")) { + throw new IllegalArgumentException("Please use [Lxxx; to define an Array type, and ref to JVM Specification for details"); + } + } +} \ No newline at end of file diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/CacheableTransformerDecorator.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/CacheableTransformerDecorator.java new file mode 100644 index 00000000..3ac05e52 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/CacheableTransformerDecorator.java @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bytebuddy; + +import com.example.agent.core.boot.AgentPackageNotFoundException; +import com.example.agent.core.boot.AgentPackagePath; +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.util.FileUtils; +import com.example.agent.core.util.IOUtils; +import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.agent.builder.ResettableClassFileTransformer; +import net.bytebuddy.utility.RandomString; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.instrument.IllegalClassFormatException; +import java.security.ProtectionDomain; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Wrapper classFileTransformer of ByteBuddy, save the enhanced bytecode to memory cache or file cache, + * and automatically load the previously generated bytecode during the second retransform, + * to solve the problem that ByteBuddy generates auxiliary classes with different random names every time. + * Allow other javaagent to enhance those classes that enhanced by cook-async agent. + */ +public class CacheableTransformerDecorator implements AgentBuilder.TransformerDecorator { + + private static final ILog LOGGER = LogManager.getLogger(CacheableTransformerDecorator.class); + + private final ClassCacheMode cacheMode; + private ClassCacheResolver cacheResolver; + + public CacheableTransformerDecorator(ClassCacheMode cacheMode) throws IOException { + this.cacheMode = cacheMode; + initClassCache(); + } + + private void initClassCache() throws IOException { + if (this.cacheMode.equals(ClassCacheMode.FILE)) { + String cacheDirBase = null; + try { + cacheDirBase = AgentPackagePath.getPath() + "/class-cache"; + } catch (AgentPackageNotFoundException e) { + throw new IOException("Can't find the root path for creating /class-cache folder."); + } + File cacheDir = new File(cacheDirBase + "/class-cache-" + RandomString.make()); + if (!cacheDir.exists()) { + cacheDir.mkdirs(); + } + if (!cacheDir.exists()) { + throw new IOException("Create class cache dir failure"); + } + + cacheResolver = new FileCacheResolver(cacheDir); + } else { + cacheResolver = new MemoryCacheResolver(); + } + } + + @Override + public ResettableClassFileTransformer decorate(ResettableClassFileTransformer classFileTransformer) { + return new ResettableClassFileTransformer.WithDelegation(classFileTransformer) { + + @Override + public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { + // load from cache + byte[] classCache = cacheResolver.getClassCache(loader, className); + if (classCache != null) { + return classCache; + } + + // transform class + classfileBuffer = classFileTransformer.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer); + + // save to cache + if (classfileBuffer != null) { + cacheResolver.putClassCache(loader, className, classfileBuffer); + } + + return classfileBuffer; + } + }; + } + + private static String getClassLoaderHash(ClassLoader loader) { + String classloader; + if (loader != null) { + classloader = Integer.toHexString(loader.hashCode()); + } else { + // classloader is null for BootstrapClassLoader + classloader = "00000000"; + } + return classloader; + } + + interface ClassCacheResolver { + + byte[] getClassCache(ClassLoader loader, String className); + + void putClassCache(ClassLoader loader, String className, byte[] classfileBuffer); + } + + static class MemoryCacheResolver implements ClassCacheResolver { + + // classloaderHashcode@className -> class bytes + private Map classCacheMap = new ConcurrentHashMap(); + + @Override + public byte[] getClassCache(ClassLoader loader, String className) { + String cacheKey = getCacheKey(loader, className); + return classCacheMap.get(cacheKey); + } + + @Override + public void putClassCache(ClassLoader loader, String className, byte[] classfileBuffer) { + String cacheKey = getCacheKey(loader, className); + classCacheMap.put(cacheKey, classfileBuffer); + } + + private String getCacheKey(ClassLoader loader, String className) { + return getClassLoaderHash(loader) + "@" + className; + } + } + + static class FileCacheResolver implements ClassCacheResolver { + + private final File cacheDir; + + FileCacheResolver(File cacheDir) { + this.cacheDir = cacheDir; + + // clean cache dir on exit + FileUtils.deleteDirectoryOnExit(cacheDir); + } + + @Override + public byte[] getClassCache(ClassLoader loader, String className) { + // load from cache + File cacheFile = getCacheFile(loader, className); + if (cacheFile.exists()) { + FileInputStream fileInputStream = null; + try { + fileInputStream = new FileInputStream(cacheFile); + return IOUtils.toByteArray(fileInputStream); + } catch (IOException e) { + LOGGER.error("load class bytes from cache file failure", e); + } finally { + IOUtils.closeQuietly(fileInputStream); + } + } + return null; + } + + @Override + public void putClassCache(ClassLoader loader, String className, byte[] classfileBuffer) { + File cacheFile = getCacheFile(loader, className); + cacheFile.getParentFile().mkdirs(); + FileOutputStream output = null; + try { + output = new FileOutputStream(cacheFile); + IOUtils.copy(new ByteArrayInputStream(classfileBuffer), output); + } catch (IOException e) { + LOGGER.error("save class bytes to cache file failure", e); + } finally { + IOUtils.closeQuietly(output); + } + } + + private File getCacheFile(ClassLoader loader, String className) { + String filename = getClassLoaderHash(loader) + "/" + className.replace('.', '/') + ".class"; + return new File(cacheDir, filename); + } + + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/ClassCacheMode.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/ClassCacheMode.java new file mode 100644 index 00000000..a9e1eae4 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/ClassCacheMode.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bytebuddy; + +/** + * ByteBuddy class cache mode + */ +public enum ClassCacheMode { + FILE, MEMORY +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/ReturnTypeNameMatch.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/ReturnTypeNameMatch.java new file mode 100644 index 00000000..1bac3492 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/bytebuddy/ReturnTypeNameMatch.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.bytebuddy; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * Return Type match. Similar with {@link net.bytebuddy.matcher.ElementMatchers#returns}, the only different between + * them is this match use {@link String} to declare the type, instead of {@link Class}. This can avoid the classloader + * risk. + *

+ * 2019-08-15 + */ +public class ReturnTypeNameMatch implements ElementMatcher { + + /** + * the target return type + */ + private String returnTypeName; + + /** + * declare the match target method with the certain type. + * + * @param returnTypeName target return type + */ + private ReturnTypeNameMatch(String returnTypeName) { + ArrayTypeNameChecker.check(returnTypeName); + this.returnTypeName = returnTypeName; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean matches(MethodDescription target) { + return target.getReturnType().asErasure().getName().equals(returnTypeName); + } + + /** + * The static method to create {@link ReturnTypeNameMatch} This is a delegate method to follow byte-buddy {@link + * ElementMatcher}'s code style. + * + * @param returnTypeName target return type + * @return new {@link ReturnTypeNameMatch} instance. + */ + public static ElementMatcher returnsWithType(String returnTypeName) { + return new ReturnTypeNameMatch(returnTypeName); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/exception/IllegalPluginDefineException.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/exception/IllegalPluginDefineException.java new file mode 100644 index 00000000..a80470e1 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/exception/IllegalPluginDefineException.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.exception; + +/** + * Thrown to indicate that a illegal format plugin definition has been defined in cook-async-plugin.define. + */ +public class IllegalPluginDefineException extends Exception { + + public IllegalPluginDefineException(String define) { + super("Illegal plugin define : " + define); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/ConstructorInterceptPoint.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/ConstructorInterceptPoint.java new file mode 100644 index 00000000..3f0e5928 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/ConstructorInterceptPoint.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * One of the three "Intercept Point". "Intercept Point" is a definition about where and how intercept happens. In this + * "Intercept Point", the definition targets class's constructors, and the interceptor. + *

+ * ref to two others: {@link StaticMethodsInterceptPoint} and {@link InstanceMethodsInterceptPoint} + *

+ */ +public interface ConstructorInterceptPoint { + + /** + * Constructor matcher + * + * @return matcher instance. + */ + ElementMatcher getConstructorMatcher(); + + /** + * @return represents a class name, the class instance must be a instance of {@link + * com.example.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor} + */ + String getConstructorInterceptor(); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/DeclaredInstanceMethodsInterceptPoint.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/DeclaredInstanceMethodsInterceptPoint.java new file mode 100644 index 00000000..28d83a0c --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/DeclaredInstanceMethodsInterceptPoint.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor; + +/** + * this interface for those who only want to enhance declared method in case of some unexpected issue, such as spring + * controller + */ +public interface DeclaredInstanceMethodsInterceptPoint extends InstanceMethodsInterceptPoint { +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/EnhanceException.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/EnhanceException.java new file mode 100644 index 00000000..a728ee3a --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/EnhanceException.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor; + +import com.example.agent.core.plugin.PluginException; + +public class EnhanceException extends PluginException { + + private static final long serialVersionUID = -2234782755784217255L; + + public EnhanceException(String message) { + super(message); + } + + public EnhanceException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/InstanceMethodsInterceptPoint.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/InstanceMethodsInterceptPoint.java new file mode 100644 index 00000000..6d5ecd07 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/InstanceMethodsInterceptPoint.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * One of the three "Intercept Point". "Intercept Point" is a definition about where and how intercept happens. In this + * "Intercept Point", the definition targets class's instance methods, and the interceptor. + *

+ * ref to two others: {@link ConstructorInterceptPoint} and {@link StaticMethodsInterceptPoint} + *

+ */ +public interface InstanceMethodsInterceptPoint { + + /** + * class instance methods matcher. + * + * @return methods matcher + */ + ElementMatcher getMethodsMatcher(); + + /** + * @return represents a class name, the class instance must instanceof InstanceMethodsAroundInterceptor. + */ + String getMethodsInterceptor(); + + boolean isOverrideArgs(); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/StaticMethodsInterceptPoint.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/StaticMethodsInterceptPoint.java new file mode 100644 index 00000000..0653def7 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/StaticMethodsInterceptPoint.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * One of the three "Intercept Point". "Intercept Point" is a definition about where and how intercept happens. In this + * "Intercept Point", the definition targets class's static methods, and the interceptor. + *

+ * ref to two others: {@link ConstructorInterceptPoint} and {@link InstanceMethodsInterceptPoint} + *

+ */ +public interface StaticMethodsInterceptPoint { + + /** + * static methods matcher. + * + * @return matcher instance. + */ + ElementMatcher getMethodsMatcher(); + + /** + * @return represents a class name, the class instance must instanceof StaticMethodsAroundInterceptor. + */ + String getMethodsInterceptor(); + + boolean isOverrideArgs(); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/BootstrapInterRuntimeAssist.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/BootstrapInterRuntimeAssist.java new file mode 100644 index 00000000..5e1f147f --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/BootstrapInterRuntimeAssist.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance; + +import com.example.agent.core.plugin.bootstrap.IBootstrapLog; + +import java.io.PrintStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * This assist help all bootstrap class core interceptor. + */ +public class BootstrapInterRuntimeAssist { + + private static final String AGENT_CLASSLOADER_DEFAULT = "com.example.agent.core.plugin.loader.AgentClassLoader"; + private static final String DEFAULT_AGENT_CLASSLOADER_INSTANCE = "DEFAULT_LOADER"; + private static final String LOG_MANAGER_CLASS = "com.example.agent.core.plugin.bootstrap.BootstrapPluginLogBridge"; + private static final String LOG_MANAGER_GET_LOGGER_METHOD = "getLogger"; + private static final PrintStream OUT = System.out; + + public static ClassLoader getAgentClassLoader() { + try { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + if (loader == null) { + return null; + } + Class agentClassLoaderClass = Class.forName(AGENT_CLASSLOADER_DEFAULT, true, loader); + Field defaultLoaderField = agentClassLoaderClass.getDeclaredField(DEFAULT_AGENT_CLASSLOADER_INSTANCE); + defaultLoaderField.setAccessible(true); + ClassLoader defaultAgentClassLoader = (ClassLoader) defaultLoaderField.get(null); + + return defaultAgentClassLoader; + } catch (Exception e) { + e.printStackTrace(OUT); + return null; + } + } + + public static IBootstrapLog getLogger(ClassLoader defaultAgentClassLoader, String interceptor) { + try { + Class logManagerClass = Class.forName(LOG_MANAGER_CLASS, true, defaultAgentClassLoader); + Method getLogger = logManagerClass.getMethod(LOG_MANAGER_GET_LOGGER_METHOD, String.class); + return (IBootstrapLog) getLogger.invoke(null, interceptor + "_internal"); + } catch (Exception e) { + e.printStackTrace(OUT); + return null; + } + } + + public static T createInterceptor(ClassLoader defaultAgentClassLoader, String className, IBootstrapLog log) { + try { + Class interceptor = Class.forName(className, true, defaultAgentClassLoader); + return (T) interceptor.newInstance(); + } catch (Exception e) { + log.error(e, "Interceptor[{}] not found", className); + } + return null; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/ClassEnhancePluginDefine.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/ClassEnhancePluginDefine.java new file mode 100644 index 00000000..2a97d7d8 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/ClassEnhancePluginDefine.java @@ -0,0 +1,238 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.AbstractClassEnhancePluginDefine; +import com.example.agent.core.plugin.EnhanceContext; +import com.example.agent.core.plugin.PluginException; +import com.example.agent.core.plugin.bootstrap.BootstrapInstrumentBoost; +import com.example.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import com.example.agent.core.plugin.interceptor.DeclaredInstanceMethodsInterceptPoint; +import com.example.agent.core.plugin.interceptor.EnhanceException; +import com.example.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import com.example.agent.core.plugin.interceptor.StaticMethodsInterceptPoint; +import com.example.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point; +import com.example.agent.core.plugin.interceptor.v2.StaticMethodsInterceptV2Point; +import com.example.agent.core.util.StringUtil; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.DynamicType; +import net.bytebuddy.implementation.FieldAccessor; +import net.bytebuddy.implementation.MethodDelegation; +import net.bytebuddy.implementation.SuperMethodCall; +import net.bytebuddy.implementation.bind.annotation.Morph; +import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.ElementMatchers; + +import static net.bytebuddy.jar.asm.Opcodes.ACC_PRIVATE; +import static net.bytebuddy.jar.asm.Opcodes.ACC_VOLATILE; +import static net.bytebuddy.matcher.ElementMatchers.isStatic; +import static net.bytebuddy.matcher.ElementMatchers.not; + +/** + * This class controls all enhance operations, including enhance constructors, instance methods and static methods. All + * the enhances base on three types interceptor point: {@link ConstructorInterceptPoint}, {@link + * InstanceMethodsInterceptPoint} and {@link StaticMethodsInterceptPoint} If plugin is going to enhance constructors, + * instance methods, or both, {@link ClassEnhancePluginDefine} will add a field of {@link Object} type. + */ +public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePluginDefine { + + private static final ILog LOGGER = LogManager.getLogger(ClassEnhancePluginDefine.class); + + /** + * Enhance a class to intercept constructors and class instance methods. + * + * @param typeDescription target class description + * @param newClassBuilder byte-buddy's builder to manipulate class bytecode. + * @return new byte-buddy's builder for further manipulation. + */ + @Override + protected DynamicType.Builder enhanceInstance(TypeDescription typeDescription, + DynamicType.Builder newClassBuilder, ClassLoader classLoader, + EnhanceContext context) throws PluginException { + ConstructorInterceptPoint[] constructorInterceptPoints = getConstructorsInterceptPoints(); + InstanceMethodsInterceptPoint[] instanceMethodsInterceptPoints = getInstanceMethodsInterceptPoints(); + String enhanceOriginClassName = typeDescription.getTypeName(); + boolean existedConstructorInterceptPoint = false; + if (constructorInterceptPoints != null && constructorInterceptPoints.length > 0) { + existedConstructorInterceptPoint = true; + } + boolean existedMethodsInterceptPoints = false; + if (instanceMethodsInterceptPoints != null && instanceMethodsInterceptPoints.length > 0) { + existedMethodsInterceptPoints = true; + } + + /** + * nothing need to be enhanced in class instance, maybe need enhance static methods. + */ + if (!existedConstructorInterceptPoint && !existedMethodsInterceptPoints) { + return newClassBuilder; + } + + /** + * Manipulate class source code.
+ * + * new class need:
+ * 1.Add field, name {@link #CONTEXT_ATTR_NAME}. + * 2.Add a field accessor for this field. + * + * And make sure the source codes manipulation only occurs once. + * + */ + if (!typeDescription.isAssignableTo(EnhancedInstance.class)) { + if (!context.isObjectExtended()) { + newClassBuilder = newClassBuilder.defineField( + CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE | ACC_VOLATILE) + .implement(EnhancedInstance.class) + .intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME)); + context.extendObjectCompleted(); + } + } + + /** + * 2. enhance constructors + */ + if (existedConstructorInterceptPoint) { + for (ConstructorInterceptPoint constructorInterceptPoint : constructorInterceptPoints) { + if (isBootstrapInstrumentation()) { + newClassBuilder = newClassBuilder.constructor(constructorInterceptPoint.getConstructorMatcher()) + .intercept(SuperMethodCall.INSTANCE.andThen(MethodDelegation.withDefaultConfiguration() + .to(BootstrapInstrumentBoost + .forInternalDelegateClass(constructorInterceptPoint + .getConstructorInterceptor())))); + } else { + newClassBuilder = newClassBuilder.constructor(constructorInterceptPoint.getConstructorMatcher()) + .intercept(SuperMethodCall.INSTANCE.andThen(MethodDelegation.withDefaultConfiguration() + .to(new ConstructorInter(constructorInterceptPoint + .getConstructorInterceptor(), classLoader)))); + } + } + } + + /** + * 3. enhance instance methods + */ + if (existedMethodsInterceptPoints) { + for (InstanceMethodsInterceptPoint instanceMethodsInterceptPoint : instanceMethodsInterceptPoints) { + String interceptor = instanceMethodsInterceptPoint.getMethodsInterceptor(); + if (StringUtil.isEmpty(interceptor)) { + throw new EnhanceException("no InstanceMethodsAroundInterceptor define to enhance class " + enhanceOriginClassName); + } + ElementMatcher.Junction junction = not(isStatic()).and(instanceMethodsInterceptPoint.getMethodsMatcher()); + if (instanceMethodsInterceptPoint instanceof DeclaredInstanceMethodsInterceptPoint) { + junction = junction.and(ElementMatchers.isDeclaredBy(typeDescription)); + } + if (instanceMethodsInterceptPoint.isOverrideArgs()) { + if (isBootstrapInstrumentation()) { + newClassBuilder = newClassBuilder.method(junction) + .intercept(MethodDelegation.withDefaultConfiguration() + .withBinders(Morph.Binder.install(OverrideCallable.class)) + .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor))); + } else { + newClassBuilder = newClassBuilder.method(junction) + .intercept(MethodDelegation.withDefaultConfiguration() + .withBinders(Morph.Binder.install(OverrideCallable.class)) + .to(new InstMethodsInterWithOverrideArgs(interceptor, classLoader))); + } + } else { + if (isBootstrapInstrumentation()) { + newClassBuilder = newClassBuilder.method(junction) + .intercept(MethodDelegation.withDefaultConfiguration() + .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor))); + } else { + newClassBuilder = newClassBuilder.method(junction) + .intercept(MethodDelegation.withDefaultConfiguration() + .to(new InstMethodsInter(interceptor, classLoader))); + } + } + } + } + + return newClassBuilder; + } + + /** + * Enhance a class to intercept class static methods. + * + * @param typeDescription target class description + * @param newClassBuilder byte-buddy's builder to manipulate class bytecode. + * @return new byte-buddy's builder for further manipulation. + */ + @Override + protected DynamicType.Builder enhanceClass(TypeDescription typeDescription, DynamicType.Builder newClassBuilder, + ClassLoader classLoader) throws PluginException { + StaticMethodsInterceptPoint[] staticMethodsInterceptPoints = getStaticMethodsInterceptPoints(); + String enhanceOriginClassName = typeDescription.getTypeName(); + if (staticMethodsInterceptPoints == null || staticMethodsInterceptPoints.length == 0) { + return newClassBuilder; + } + + for (StaticMethodsInterceptPoint staticMethodsInterceptPoint : staticMethodsInterceptPoints) { + String interceptor = staticMethodsInterceptPoint.getMethodsInterceptor(); + if (StringUtil.isEmpty(interceptor)) { + throw new EnhanceException("no StaticMethodsAroundInterceptor define to enhance class " + enhanceOriginClassName); + } + + if (staticMethodsInterceptPoint.isOverrideArgs()) { + if (isBootstrapInstrumentation()) { + newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher())) + .intercept(MethodDelegation.withDefaultConfiguration() + .withBinders(Morph.Binder.install(OverrideCallable.class)) + .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor))); + } else { + newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher())) + .intercept(MethodDelegation.withDefaultConfiguration() + .withBinders(Morph.Binder.install(OverrideCallable.class)) + .to(new StaticMethodsInterWithOverrideArgs(interceptor))); + } + } else { + if (isBootstrapInstrumentation()) { + newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher())) + .intercept(MethodDelegation.withDefaultConfiguration() + .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor))); + } else { + newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher())) + .intercept(MethodDelegation.withDefaultConfiguration() + .to(new StaticMethodsInter(interceptor))); + } + } + + } + + return newClassBuilder; + } + + /** + * @return null, means enhance no v2 instance methods. + */ + @Override + public InstanceMethodsInterceptV2Point[] getInstanceMethodsInterceptV2Points() { + return null; + } + + /** + * @return null, means enhance no v2 static methods. + */ + @Override + public StaticMethodsInterceptV2Point[] getStaticMethodsInterceptV2Points() { + return null; + } + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/ClassInstanceMethodsEnhancePluginDefine.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/ClassInstanceMethodsEnhancePluginDefine.java new file mode 100644 index 00000000..45ce1cdb --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/ClassInstanceMethodsEnhancePluginDefine.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance; + +import com.example.agent.core.plugin.interceptor.StaticMethodsInterceptPoint; + +/** + * Plugins, which only need enhance class instance methods. Actually, inherit from {@link + * ClassInstanceMethodsEnhancePluginDefine} has no differences with inherit from {@link ClassEnhancePluginDefine}. Just + * override {@link ClassEnhancePluginDefine#getStaticMethodsInterceptPoints}, and return NULL, which means nothing to + * enhance. + */ +public abstract class ClassInstanceMethodsEnhancePluginDefine extends ClassEnhancePluginDefine { + + /** + * @return null, means enhance no static methods. + */ + @Override + public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() { + return null; + } + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/ClassStaticMethodsEnhancePluginDefine.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/ClassStaticMethodsEnhancePluginDefine.java new file mode 100644 index 00000000..cae02f09 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/ClassStaticMethodsEnhancePluginDefine.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance; + +import com.example.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import com.example.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; + +/** + * Plugins, which only need enhance class static methods. Actually, inherit from {@link + * ClassStaticMethodsEnhancePluginDefine} has no differences with inherit from {@link ClassEnhancePluginDefine}. Just + * override {@link ClassEnhancePluginDefine#getConstructorsInterceptPoints} and {@link + * ClassEnhancePluginDefine#getInstanceMethodsInterceptPoints}, and return NULL, which means nothing to enhance. + */ +public abstract class ClassStaticMethodsEnhancePluginDefine extends ClassEnhancePluginDefine { + + /** + * @return null, means enhance no constructors. + */ + @Override + public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return null; + } + + /** + * @return null, means enhance no instance methods. + */ + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return null; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/ConstructorInter.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/ConstructorInter.java new file mode 100644 index 00000000..6402866a --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/ConstructorInter.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.PluginException; +import com.example.agent.core.plugin.loader.InterceptorInstanceLoader; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.This; + +/** + * The actual byte-buddy's interceptor to intercept constructor methods. In this class, it provides a bridge between + * byte-buddy and sky-walking plugin. + */ +public class ConstructorInter { + + private static final ILog LOGGER = LogManager.getLogger(ConstructorInter.class); + + /** + * An {@link InstanceConstructorInterceptor} This name should only stay in {@link String}, the real {@link Class} + * type will trigger classloader failure. If you want to know more, please check on books about Classloader or + * Classloader appointment mechanism. + */ + private InstanceConstructorInterceptor interceptor; + + /** + * @param constructorInterceptorClassName class full name. + */ + public ConstructorInter(String constructorInterceptorClassName, ClassLoader classLoader) throws PluginException { + try { + interceptor = InterceptorInstanceLoader.load(constructorInterceptorClassName, classLoader); + } catch (Throwable t) { + throw new PluginException("Can't create InstanceConstructorInterceptorV2.", t); + } + } + + /** + * Intercept the target constructor. + * + * @param obj target class instance. + * @param allArguments all constructor arguments + */ + @RuntimeType + public void intercept(@This Object obj, @AllArguments Object[] allArguments) { + try { + EnhancedInstance targetObject = (EnhancedInstance) obj; + + interceptor.onConstruct(targetObject, allArguments); + } catch (Throwable t) { + LOGGER.error("ConstructorInter failure.", t); + } + + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/EnhancedInstance.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/EnhancedInstance.java new file mode 100644 index 00000000..f6aa8593 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/EnhancedInstance.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance; + +public interface EnhancedInstance { + + Object getCookDynamicField(); + + void setCookDynamicField(Object value); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/InstMethodsInter.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/InstMethodsInter.java new file mode 100644 index 00000000..af54cea8 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/InstMethodsInter.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.PluginException; +import com.example.agent.core.plugin.loader.InterceptorInstanceLoader; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.SuperCall; +import net.bytebuddy.implementation.bind.annotation.This; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +/** + * The actual byte-buddy's interceptor to intercept class instance methods. In this class, it provides a bridge between + * byte-buddy and sky-walking plugin. + */ +public class InstMethodsInter { + + private static final ILog LOGGER = LogManager.getLogger(InstMethodsInter.class); + + /** + * An {@link InstanceMethodsAroundInterceptor} This name should only stay in {@link String}, the real {@link Class} + * type will trigger classloader failure. If you want to know more, please check on books about Classloader or + * Classloader appointment mechanism. + */ + private InstanceMethodsAroundInterceptor interceptor; + + /** + * @param instanceMethodsAroundInterceptorClassName class full name. + */ + public InstMethodsInter(String instanceMethodsAroundInterceptorClassName, ClassLoader classLoader) { + try { + interceptor = InterceptorInstanceLoader.load(instanceMethodsAroundInterceptorClassName, classLoader); + } catch (Throwable t) { + throw new PluginException("Can't create InstanceMethodsAroundInterceptor.", t); + } + } + + /** + * Intercept the target instance method. + * + * @param obj target class instance. + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target instance method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public Object intercept(@This Object obj, @AllArguments Object[] allArguments, @SuperCall Callable zuper, + @Origin Method method) throws Throwable { + EnhancedInstance targetObject = (EnhancedInstance) obj; + + MethodInterceptResult result = new MethodInterceptResult(); + try { + interceptor.beforeMethod(targetObject, method, allArguments, method.getParameterTypes(), result); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before method[{}] intercept failure", obj.getClass(), method.getName()); + } + + Object ret = null; + try { + if (!result.isContinue()) { + ret = result._ret(); + } else { + ret = zuper.call(); + } + } catch (Throwable t) { + try { + interceptor.handleMethodException(targetObject, method, allArguments, method.getParameterTypes(), t); + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle method[{}] exception failure", obj.getClass(), method.getName()); + } + throw t; + } finally { + try { + ret = interceptor.afterMethod(targetObject, method, allArguments, method.getParameterTypes(), ret); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + return ret; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/InstMethodsInterWithOverrideArgs.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/InstMethodsInterWithOverrideArgs.java new file mode 100644 index 00000000..1aae7652 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/InstMethodsInterWithOverrideArgs.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.PluginException; +import com.example.agent.core.plugin.loader.InterceptorInstanceLoader; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Morph; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.This; + +import java.lang.reflect.Method; + +/** + * The actual byte-buddy's interceptor to intercept class instance methods. In this class, it provides a bridge between + * byte-buddy and sky-walking plugin. + */ +public class InstMethodsInterWithOverrideArgs { + + private static final ILog LOGGER = LogManager.getLogger(InstMethodsInterWithOverrideArgs.class); + + /** + * An {@link InstanceMethodsAroundInterceptor} This name should only stay in {@link String}, the real {@link Class} + * type will trigger classloader failure. If you want to know more, please check on books about Classloader or + * Classloader appointment mechanism. + */ + private InstanceMethodsAroundInterceptor interceptor; + + /** + * @param instanceMethodsAroundInterceptorClassName class full name. + */ + public InstMethodsInterWithOverrideArgs(String instanceMethodsAroundInterceptorClassName, ClassLoader classLoader) { + try { + interceptor = InterceptorInstanceLoader.load(instanceMethodsAroundInterceptorClassName, classLoader); + } catch (Throwable t) { + throw new PluginException("Can't create InstanceMethodsAroundInterceptor.", t); + } + } + + /** + * Intercept the target instance method. + * + * @param obj target class instance. + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target instance method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public Object intercept(@This Object obj, @AllArguments Object[] allArguments, @Origin Method method, + @Morph OverrideCallable zuper) throws Throwable { + EnhancedInstance targetObject = (EnhancedInstance) obj; + + MethodInterceptResult result = new MethodInterceptResult(); + try { + interceptor.beforeMethod(targetObject, method, allArguments, method.getParameterTypes(), result); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before method[{}] intercept failure", obj.getClass(), method.getName()); + } + + Object ret = null; + try { + if (!result.isContinue()) { + ret = result._ret(); + } else { + ret = zuper.call(allArguments); + } + } catch (Throwable t) { + try { + interceptor.handleMethodException(targetObject, method, allArguments, method.getParameterTypes(), t); + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle method[{}] exception failure", obj.getClass(), method.getName()); + } + throw t; + } finally { + try { + ret = interceptor.afterMethod(targetObject, method, allArguments, method.getParameterTypes(), ret); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + return ret; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/InstanceConstructorInterceptor.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/InstanceConstructorInterceptor.java new file mode 100644 index 00000000..862a2e4d --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/InstanceConstructorInterceptor.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance; + +/** + * The instance constructor's interceptor interface. Any plugin, which wants to intercept constructor, must implement + * this interface. + *

+ */ +public interface InstanceConstructorInterceptor { + + /** + * Called after the origin constructor invocation. + */ + void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable; +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/InstanceMethodsAroundInterceptor.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/InstanceMethodsAroundInterceptor.java new file mode 100644 index 00000000..c449674a --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/InstanceMethodsAroundInterceptor.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance; + +import java.lang.reflect.Method; + +/** + * A interceptor, which intercept method's invocation. The target methods will be defined in {@link + * ClassEnhancePluginDefine}'s subclass, most likely in {@link ClassInstanceMethodsEnhancePluginDefine} + */ +public interface InstanceMethodsAroundInterceptor { + + /** + * called before target method invocation. + * + * @param result change this result, if you want to truncate the method. + */ + void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + MethodInterceptResult result) throws Throwable; + + /** + * called after target method invocation. Even method's invocation triggers an exception. + * + * @param ret the method's original return value. May be null if the method triggers an exception. + * @return the method's actual return value. + */ + Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + Object ret) throws Throwable; + + /** + * called when occur exception. + * + * @param t the exception occur. + */ + void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, + Class[] argumentsTypes, Throwable t); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/MethodInterceptResult.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/MethodInterceptResult.java new file mode 100644 index 00000000..cee5a76c --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/MethodInterceptResult.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance; + +import java.lang.reflect.Method; + +/** + * This is a method return value manipulator. When a interceptor's method, such as {@link + * InstanceMethodsAroundInterceptor#beforeMethod(EnhancedInstance, Method, Object[], Class[], MethodInterceptResult)} + * (org.apache.skywalking.apm.agent.core.plugin.interceptor.EnhancedClassInstanceContext, has this as a method argument, + * the interceptor can manipulate the method's return value.

The new value set to this object, by {@link + * MethodInterceptResult#defineReturnValue(Object)}, will override the origin return value. + */ +public class MethodInterceptResult { + + private boolean isContinue = true; + + private Object ret = null; + + /** + * define the new return value. + * + * @param ret new return value. + */ + public void defineReturnValue(Object ret) { + this.isContinue = false; + this.ret = ret; + } + + /** + * @return true, will trigger method interceptor({@link InstMethodsInter} and {@link StaticMethodsInter}) to invoke + * the origin method. Otherwise, not. + */ + public boolean isContinue() { + return isContinue; + } + + /** + * @return the new return value. + */ + public Object _ret() { + return ret; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/OverrideCallable.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/OverrideCallable.java new file mode 100644 index 00000000..4765bb74 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/OverrideCallable.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance; + +public interface OverrideCallable { + + Object call(Object[] args); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/StaticMethodsAroundInterceptor.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/StaticMethodsAroundInterceptor.java new file mode 100644 index 00000000..ad030447 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/StaticMethodsAroundInterceptor.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance; + +import java.lang.reflect.Method; + +/** + * The static method's interceptor interface. Any plugin, which wants to intercept static methods, must implement this + * interface. + */ +public interface StaticMethodsAroundInterceptor { + + /** + * called before target method invocation. + * + * @param result change this result, if you want to truncate the method. + */ + void beforeMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, + MethodInterceptResult result); + + /** + * called after target method invocation. Even method's invocation triggers an exception. + * + * @param ret the method's original return value. + * @return the method's actual return value. + */ + Object afterMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, Object ret); + + /** + * called when occur exception. + * + * @param t the exception occur. + */ + void handleMethodException(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, + Throwable t); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/StaticMethodsInter.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/StaticMethodsInter.java new file mode 100644 index 00000000..b357bd40 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/StaticMethodsInter.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.loader.InterceptorInstanceLoader; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.SuperCall; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +/** + * The actual byte-buddy's interceptor to intercept class static methods. In this class, it provides a bridge between + * byte-buddy and sky-walking plugin. + */ +public class StaticMethodsInter { + + private static final ILog LOGGER = LogManager.getLogger(StaticMethodsInter.class); + + /** + * A class full name, and instanceof {@link StaticMethodsAroundInterceptor} This name should only stay in {@link + * String}, the real {@link Class} type will trigger classloader failure. If you want to know more, please check on + * books about Classloader or Classloader appointment mechanism. + */ + private String staticMethodsAroundInterceptorClassName; + + /** + * Set the name of {@link StaticMethodsInter#staticMethodsAroundInterceptorClassName} + * + * @param staticMethodsAroundInterceptorClassName class full name. + */ + public StaticMethodsInter(String staticMethodsAroundInterceptorClassName) { + this.staticMethodsAroundInterceptorClassName = staticMethodsAroundInterceptorClassName; + } + + /** + * Intercept the target static method. + * + * @param clazz target class + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target static method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public Object intercept(@Origin Class clazz, @AllArguments Object[] allArguments, @Origin Method method, + @SuperCall Callable zuper) throws Throwable { + StaticMethodsAroundInterceptor interceptor = InterceptorInstanceLoader.load(staticMethodsAroundInterceptorClassName, clazz + .getClassLoader()); + + MethodInterceptResult result = new MethodInterceptResult(); + try { + interceptor.beforeMethod(clazz, method, allArguments, method.getParameterTypes(), result); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before static method[{}] intercept failure", clazz, method.getName()); + } + + Object ret = null; + try { + if (!result.isContinue()) { + ret = result._ret(); + } else { + ret = zuper.call(); + } + } catch (Throwable t) { + try { + interceptor.handleMethodException(clazz, method, allArguments, method.getParameterTypes(), t); + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle static method[{}] exception failure", clazz, method.getName(), t2.getMessage()); + } + throw t; + } finally { + try { + ret = interceptor.afterMethod(clazz, method, allArguments, method.getParameterTypes(), ret); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after static method[{}] intercept failure:{}", clazz, method.getName(), t.getMessage()); + } + } + return ret; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/StaticMethodsInterWithOverrideArgs.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/StaticMethodsInterWithOverrideArgs.java new file mode 100644 index 00000000..59e310e4 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/StaticMethodsInterWithOverrideArgs.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.loader.InterceptorInstanceLoader; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Morph; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; + +import java.lang.reflect.Method; + +/** + * The actual byte-buddy's interceptor to intercept class static methods. In this class, it provides a bridge between + * byte-buddy and sky-walking plugin. + */ +public class StaticMethodsInterWithOverrideArgs { + + private static final ILog LOGGER = LogManager.getLogger(StaticMethodsInterWithOverrideArgs.class); + + /** + * A class full name, and instanceof {@link StaticMethodsAroundInterceptor} This name should only stay in {@link + * String}, the real {@link Class} type will trigger classloader failure. If you want to know more, please check on + * books about Classloader or Classloader appointment mechanism. + */ + private String staticMethodsAroundInterceptorClassName; + + /** + * Set the name of {@link StaticMethodsInterWithOverrideArgs#staticMethodsAroundInterceptorClassName} + * + * @param staticMethodsAroundInterceptorClassName class full name. + */ + public StaticMethodsInterWithOverrideArgs(String staticMethodsAroundInterceptorClassName) { + this.staticMethodsAroundInterceptorClassName = staticMethodsAroundInterceptorClassName; + } + + /** + * Intercept the target static method. + * + * @param clazz target class + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target static method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public Object intercept(@Origin Class clazz, @AllArguments Object[] allArguments, @Origin Method method, + @Morph OverrideCallable zuper) throws Throwable { + StaticMethodsAroundInterceptor interceptor = InterceptorInstanceLoader.load(staticMethodsAroundInterceptorClassName, clazz + .getClassLoader()); + + MethodInterceptResult result = new MethodInterceptResult(); + try { + interceptor.beforeMethod(clazz, method, allArguments, method.getParameterTypes(), result); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before static method[{}] intercept failure", clazz, method.getName()); + } + + Object ret = null; + try { + if (!result.isContinue()) { + ret = result._ret(); + } else { + ret = zuper.call(allArguments); + } + } catch (Throwable t) { + try { + interceptor.handleMethodException(clazz, method, allArguments, method.getParameterTypes(), t); + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle static method[{}] exception failure", clazz, method.getName(), t2.getMessage()); + } + throw t; + } finally { + try { + ret = interceptor.afterMethod(clazz, method, allArguments, method.getParameterTypes(), ret); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after static method[{}] intercept failure:{}", clazz, method.getName(), t.getMessage()); + } + } + return ret; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/ClassEnhancePluginDefineV2.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/ClassEnhancePluginDefineV2.java new file mode 100644 index 00000000..5740976a --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/ClassEnhancePluginDefineV2.java @@ -0,0 +1,207 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance.v2; + +import com.example.agent.core.plugin.AbstractClassEnhancePluginDefine; +import com.example.agent.core.plugin.EnhanceContext; +import com.example.agent.core.plugin.PluginException; +import com.example.agent.core.plugin.bootstrap.BootstrapInstrumentBoost; +import com.example.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import com.example.agent.core.plugin.interceptor.EnhanceException; +import com.example.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import com.example.agent.core.plugin.interceptor.StaticMethodsInterceptPoint; +import com.example.agent.core.plugin.interceptor.enhance.ConstructorInter; +import com.example.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import com.example.agent.core.plugin.interceptor.enhance.OverrideCallable; +import com.example.agent.core.plugin.interceptor.v2.ConstructorInterceptV2Point; +import com.example.agent.core.plugin.interceptor.v2.DeclaredInstanceMethodsInterceptV2Point; +import com.example.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point; +import com.example.agent.core.plugin.interceptor.v2.StaticMethodsInterceptV2Point; +import com.example.agent.core.util.StringUtil; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.DynamicType; +import net.bytebuddy.implementation.FieldAccessor; +import net.bytebuddy.implementation.MethodDelegation; +import net.bytebuddy.implementation.SuperMethodCall; +import net.bytebuddy.implementation.bind.annotation.Morph; +import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.ElementMatchers; + +import static net.bytebuddy.jar.asm.Opcodes.ACC_PRIVATE; +import static net.bytebuddy.jar.asm.Opcodes.ACC_VOLATILE; +import static net.bytebuddy.matcher.ElementMatchers.isStatic; +import static net.bytebuddy.matcher.ElementMatchers.not; + +/** + * This class controls all enhance operations, including enhance constructors, instance methods and static methods. All + * the enhances base on three types interceptor point: {@link ConstructorInterceptV2Point}, {@link + * InstanceMethodsInterceptV2Point} and {@link StaticMethodsInterceptV2Point} If plugin is going to enhance constructors, + * instance methods, or both, {@link ClassEnhancePluginDefineV2} will add a field of {@link Object} type. + */ +public abstract class ClassEnhancePluginDefineV2 extends AbstractClassEnhancePluginDefine { + + @Override + protected DynamicType.Builder enhanceClass(TypeDescription typeDescription, + DynamicType.Builder newClassBuilder, + ClassLoader classLoader) throws PluginException { + StaticMethodsInterceptV2Point[] staticMethodsInterceptV2Points = getStaticMethodsInterceptV2Points(); + String enhanceOriginClassName = typeDescription.getTypeName(); + if (staticMethodsInterceptV2Points == null || staticMethodsInterceptV2Points.length == 0) { + return newClassBuilder; + } + + for (StaticMethodsInterceptV2Point staticMethodsInterceptV2Point : staticMethodsInterceptV2Points) { + String interceptor = staticMethodsInterceptV2Point.getMethodsInterceptorV2(); + if (StringUtil.isEmpty(interceptor)) { + throw new EnhanceException( + "no StaticMethodsAroundInterceptorV2 define to enhance class " + enhanceOriginClassName); + } + + if (staticMethodsInterceptV2Point.isOverrideArgs()) { + if (isBootstrapInstrumentation()) { + newClassBuilder = newClassBuilder.method( + isStatic().and(staticMethodsInterceptV2Point.getMethodsMatcher())) + .intercept(MethodDelegation.withDefaultConfiguration() + .withBinders(Morph.Binder.install(OverrideCallable.class)) + .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor))); + } else { + newClassBuilder = newClassBuilder.method( + isStatic().and(staticMethodsInterceptV2Point.getMethodsMatcher())) + .intercept(MethodDelegation.withDefaultConfiguration() + .withBinders(Morph.Binder.install(OverrideCallable.class)) + .to(new StaticMethodsInterV2WithOverrideArgs(interceptor))); + } + } else { + if (isBootstrapInstrumentation()) { + newClassBuilder = newClassBuilder.method( + isStatic().and(staticMethodsInterceptV2Point.getMethodsMatcher())) + .intercept(MethodDelegation.withDefaultConfiguration() + .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor))); + } else { + newClassBuilder = newClassBuilder.method( + isStatic().and(staticMethodsInterceptV2Point.getMethodsMatcher())) + .intercept(MethodDelegation.withDefaultConfiguration() + .to(new StaticMethodsInterV2(interceptor))); + } + } + + } + + return newClassBuilder; + } + + @Override + protected DynamicType.Builder enhanceInstance(TypeDescription typeDescription, + DynamicType.Builder newClassBuilder, ClassLoader classLoader, + EnhanceContext context) throws PluginException { + ConstructorInterceptPoint[] constructorInterceptPoints = getConstructorsInterceptPoints(); + InstanceMethodsInterceptV2Point[] instanceMethodsInterceptV2Points = getInstanceMethodsInterceptV2Points(); + String enhanceOriginClassName = typeDescription.getTypeName(); + + boolean existedConstructorInterceptPoint = false; + if (constructorInterceptPoints != null && constructorInterceptPoints.length > 0) { + existedConstructorInterceptPoint = true; + } + boolean existedMethodsInterceptV2Points = false; + if (instanceMethodsInterceptV2Points != null && instanceMethodsInterceptV2Points.length > 0) { + existedMethodsInterceptV2Points = true; + } + + if (!existedConstructorInterceptPoint && !existedMethodsInterceptV2Points) { + return newClassBuilder; + } + + if (!typeDescription.isAssignableTo(EnhancedInstance.class)) { + if (!context.isObjectExtended()) { + newClassBuilder = newClassBuilder.defineField( + CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE | ACC_VOLATILE) + .implement(EnhancedInstance.class) + .intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME)); + context.extendObjectCompleted(); + } + } + + if (existedConstructorInterceptPoint) { + for (ConstructorInterceptPoint constructorInterceptPoint : constructorInterceptPoints) { + if (isBootstrapInstrumentation()) { + newClassBuilder = newClassBuilder.constructor(constructorInterceptPoint.getConstructorMatcher()) + .intercept(SuperMethodCall.INSTANCE.andThen(MethodDelegation.withDefaultConfiguration() + .to(BootstrapInstrumentBoost + .forInternalDelegateClass(constructorInterceptPoint + .getConstructorInterceptor())))); + } else { + newClassBuilder = newClassBuilder.constructor(constructorInterceptPoint.getConstructorMatcher()) + .intercept(SuperMethodCall.INSTANCE.andThen(MethodDelegation.withDefaultConfiguration() + .to(new ConstructorInter(constructorInterceptPoint + .getConstructorInterceptor(), classLoader)))); + } + } + } + + if (existedMethodsInterceptV2Points) { + for (InstanceMethodsInterceptV2Point instanceMethodsInterceptV2Point : instanceMethodsInterceptV2Points) { + String interceptor = instanceMethodsInterceptV2Point.getMethodsInterceptorV2(); + if (StringUtil.isEmpty(interceptor)) { + throw new EnhanceException( + "no InstanceMethodsAroundInterceptorV2 define to enhance class " + enhanceOriginClassName); + } + ElementMatcher.Junction junction = not(isStatic()).and( + instanceMethodsInterceptV2Point.getMethodsMatcher()); + if (instanceMethodsInterceptV2Point instanceof DeclaredInstanceMethodsInterceptV2Point) { + junction = junction.and(ElementMatchers.isDeclaredBy(typeDescription)); + } + if (instanceMethodsInterceptV2Point.isOverrideArgs()) { + if (isBootstrapInstrumentation()) { + newClassBuilder = newClassBuilder.method(junction) + .intercept(MethodDelegation.withDefaultConfiguration() + .withBinders(Morph.Binder.install(OverrideCallable.class)) + .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor))); + } else { + newClassBuilder = newClassBuilder.method(junction) + .intercept(MethodDelegation.withDefaultConfiguration() + .withBinders(Morph.Binder.install(OverrideCallable.class)) + .to(new InstMethodsInterV2WithOverrideArgs(interceptor, classLoader))); + } + } else { + if (isBootstrapInstrumentation()) { + newClassBuilder = newClassBuilder.method(junction) + .intercept(MethodDelegation.withDefaultConfiguration() + .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor))); + } else { + newClassBuilder = newClassBuilder.method(junction) + .intercept(MethodDelegation.withDefaultConfiguration() + .to(new InstMethodsInterV2(interceptor, classLoader))); + } + } + } + } + + return newClassBuilder; + } + + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return null; + } + + @Override + public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() { + return null; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/ClassInstanceMethodsEnhancePluginDefineV2.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/ClassInstanceMethodsEnhancePluginDefineV2.java new file mode 100644 index 00000000..58cee5a3 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/ClassInstanceMethodsEnhancePluginDefineV2.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance.v2; + +import com.example.agent.core.plugin.interceptor.v2.StaticMethodsInterceptV2Point; + +/** + * Plugins, which only need enhance class instance methods. Actually, inherit from {@link + * ClassInstanceMethodsEnhancePluginDefineV2} has no differences with inherit from {@link ClassEnhancePluginDefineV2}. + * Just override {@link ClassEnhancePluginDefineV2#getStaticMethodsInterceptPoints}, and return NULL, which means nothing + * to enhance. + */ +public abstract class ClassInstanceMethodsEnhancePluginDefineV2 extends ClassEnhancePluginDefineV2 { + + /** + * @return null, means enhance no v2 static methods. + */ + @Override + public StaticMethodsInterceptV2Point[] getStaticMethodsInterceptV2Points() { + return null; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/ClassStaticMethodsEnhancePluginDefineV2.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/ClassStaticMethodsEnhancePluginDefineV2.java new file mode 100644 index 00000000..52914da3 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/ClassStaticMethodsEnhancePluginDefineV2.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance.v2; + +import com.example.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import com.example.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point; + +/** + * Plugins, which only need enhance class static methods. Actually, inherit from {@link + * ClassStaticMethodsEnhancePluginDefineV2} has no differences with inherit from {@link ClassEnhancePluginDefineV2}. Just + * override {@link ClassEnhancePluginDefineV2#getConstructorsInterceptPoints} and {@link + * ClassEnhancePluginDefineV2#getInstanceMethodsInterceptV2Points}, and return NULL, which means nothing to enhance. + */ +public abstract class ClassStaticMethodsEnhancePluginDefineV2 extends ClassEnhancePluginDefineV2 { + + /** + * @return null, means enhance no constructors. + */ + @Override + public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return null; + } + + /** + * @return null, means enhance no v2 instance methods. + */ + @Override + public InstanceMethodsInterceptV2Point[] getInstanceMethodsInterceptV2Points() { + return null; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/InstMethodsInterV2.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/InstMethodsInterV2.java new file mode 100644 index 00000000..2646dfc3 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/InstMethodsInterV2.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance.v2; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.PluginException; +import com.example.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import com.example.agent.core.plugin.loader.InterceptorInstanceLoader; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.SuperCall; +import net.bytebuddy.implementation.bind.annotation.This; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +/** + * The actual byte-buddy's interceptor to intercept class instance methods. In this class, it provides a bridge between + * byte-buddy and sky-walking plugin. + */ +public class InstMethodsInterV2 { + + private static final ILog LOGGER = LogManager.getLogger(InstMethodsInterV2.class); + + private InstanceMethodsAroundInterceptorV2 interceptor; + + public InstMethodsInterV2(String instanceMethodsAroundInterceptorClassName, ClassLoader classLoader) { + try { + interceptor = InterceptorInstanceLoader.load(instanceMethodsAroundInterceptorClassName, classLoader); + } catch (Throwable t) { + throw new PluginException("Can't create InstanceMethodsAroundInterceptor.", t); + } + } + + @RuntimeType + public Object intercept(@This Object obj, @AllArguments Object[] allArguments, @SuperCall Callable zuper, + @Origin Method method) throws Throwable { + EnhancedInstance targetObject = (EnhancedInstance) obj; + + MethodInvocationContext context = new MethodInvocationContext(); + try { + interceptor.beforeMethod(targetObject, method, allArguments, method.getParameterTypes(), context); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before method[{}] intercept failure", obj.getClass(), method.getName()); + } + + Object ret = null; + try { + if (!context.isContinue()) { + ret = context._ret(); + } else { + ret = zuper.call(); + } + } catch (Throwable t) { + try { + interceptor.handleMethodException(targetObject, method, allArguments, method.getParameterTypes(), t, context); + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle method[{}] exception failure", obj.getClass(), method.getName()); + } + throw t; + } finally { + try { + ret = interceptor.afterMethod(targetObject, method, allArguments, method.getParameterTypes(), ret, context); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + return ret; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/InstMethodsInterV2WithOverrideArgs.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/InstMethodsInterV2WithOverrideArgs.java new file mode 100644 index 00000000..950ba5ae --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/InstMethodsInterV2WithOverrideArgs.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance.v2; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.PluginException; +import com.example.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import com.example.agent.core.plugin.interceptor.enhance.OverrideCallable; +import com.example.agent.core.plugin.loader.InterceptorInstanceLoader; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Morph; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.This; + +import java.lang.reflect.Method; + +/** + * The actual byte-buddy's interceptor to intercept class instance methods. In this class, it provides a bridge between + * byte-buddy and sky-walking plugin. + */ +public class InstMethodsInterV2WithOverrideArgs { + + private static final ILog LOGGER = LogManager.getLogger(InstMethodsInterV2WithOverrideArgs.class); + + /** + * An {@link InstanceMethodsAroundInterceptorV2} This name should only stay in {@link String}, the real {@link Class} + * type will trigger classloader failure. If you want to know more, please check on books about Classloader or + * Classloader appointment mechanism. + */ + private InstanceMethodsAroundInterceptorV2 interceptor; + + /** + * @param instanceMethodsAroundInterceptorClassName class full name. + */ + public InstMethodsInterV2WithOverrideArgs(String instanceMethodsAroundInterceptorClassName, ClassLoader classLoader) { + try { + interceptor = InterceptorInstanceLoader.load(instanceMethodsAroundInterceptorClassName, classLoader); + } catch (Throwable t) { + throw new PluginException("Can't create InstanceMethodsAroundInterceptor.", t); + } + } + + /** + * Intercept the target instance method. + * + * @param obj target class instance. + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target instance method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public Object intercept(@This Object obj, @AllArguments Object[] allArguments, @Origin Method method, + @Morph OverrideCallable zuper) throws Throwable { + EnhancedInstance targetObject = (EnhancedInstance) obj; + + MethodInvocationContext context = new MethodInvocationContext(); + try { + interceptor.beforeMethod(targetObject, method, allArguments, method.getParameterTypes(), context); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before method[{}] intercept failure", obj.getClass(), method.getName()); + } + + Object ret = null; + try { + if (!context.isContinue()) { + ret = context._ret(); + } else { + ret = zuper.call(allArguments); + } + } catch (Throwable t) { + try { + interceptor.handleMethodException(targetObject, method, allArguments, method.getParameterTypes(), t, context); + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle method[{}] exception failure", obj.getClass(), method.getName()); + } + throw t; + } finally { + try { + ret = interceptor.afterMethod(targetObject, method, allArguments, method.getParameterTypes(), ret, context); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after method[{}] intercept failure", obj.getClass(), method.getName()); + } + } + return ret; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/InstanceMethodsAroundInterceptorV2.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/InstanceMethodsAroundInterceptorV2.java new file mode 100644 index 00000000..fa75d590 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/InstanceMethodsAroundInterceptorV2.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance.v2; + +import com.example.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; +import com.example.agent.core.plugin.interceptor.enhance.EnhancedInstance; + +import java.lang.reflect.Method; + +/** + * A v2 interceptor, which intercept method's invocation. The target methods will be defined in {@link + * ClassEnhancePluginDefineV2}'s subclass, most likely in {@link ClassInstanceMethodsEnhancePluginDefine} + */ +public interface InstanceMethodsAroundInterceptorV2 { + + /** + * called before target method invocation. + * + * @param context the method invocation context including result context. + */ + void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + MethodInvocationContext context) throws Throwable; + + /** + * called after target method invocation. Even method's invocation triggers an exception. + * + * @param ret the method's original return value. May be null if the method triggers an exception. + * @return the method's actual return value. + */ + Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + Object ret, MethodInvocationContext context) throws Throwable; + + /** + * called when occur exception. + * + * @param t the exception occur. + */ + void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, + Class[] argumentsTypes, Throwable t, MethodInvocationContext context); + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/MethodInvocationContext.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/MethodInvocationContext.java new file mode 100644 index 00000000..2bfd482d --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/MethodInvocationContext.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance.v2; + +import com.example.agent.core.plugin.interceptor.enhance.MethodInterceptResult; +import lombok.Getter; +import lombok.Setter; + +/** + * MethodInvocationContext holds the reference to propagate it between beforeMethod and afterMethod/handleMethodException + */ +@Setter +@Getter +public class MethodInvocationContext extends MethodInterceptResult { + + /** + * A pointer for the propagating context + */ + private Object context; +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/StaticMethodsAroundInterceptorV2.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/StaticMethodsAroundInterceptorV2.java new file mode 100644 index 00000000..5d463b85 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/StaticMethodsAroundInterceptorV2.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance.v2; + +import java.lang.reflect.Method; + +/** + * The static method's interceptor v2 interface. Any plugin, which wants to intercept static methods, must implement this + * interface. + */ +public interface StaticMethodsAroundInterceptorV2 { + + /** + * called before target method invocation. + * + * @param context the method invocation context including result context. + */ + void beforeMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, + MethodInvocationContext context); + + /** + * called after target method invocation. Even method's invocation triggers an exception. + * + * @param ret the method's original return value. + * @return the method's actual return value. + */ + Object afterMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, Object ret, + MethodInvocationContext context); + + /** + * called when occur exception. + * + * @param t the exception occur. + */ + void handleMethodException(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, + Throwable t, MethodInvocationContext context); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/StaticMethodsInterV2.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/StaticMethodsInterV2.java new file mode 100644 index 00000000..e3de40e6 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/StaticMethodsInterV2.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance.v2; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.loader.InterceptorInstanceLoader; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.SuperCall; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +/** + * The actual byte-buddy's interceptor to intercept class instance methods. In this class, it provides a bridge between + * byte-buddy and sky-walking plugin. + */ +public class StaticMethodsInterV2 { + + private static final ILog LOGGER = LogManager.getLogger(StaticMethodsInterV2.class); + + /** + * A class full name, and instanceof {@link StaticMethodsAroundInterceptorV2} This name should only stay in {@link + * String}, the real {@link Class} type will trigger classloader failure. If you want to know more, please check on + * books about Classloader or Classloader appointment mechanism. + */ + private String staticMethodsAroundInterceptorClassName; + + /** + * Set the name of {@link StaticMethodsInterV2#staticMethodsAroundInterceptorClassName} + * + * @param staticMethodsAroundInterceptorClassName class full name. + */ + public StaticMethodsInterV2(String staticMethodsAroundInterceptorClassName) { + this.staticMethodsAroundInterceptorClassName = staticMethodsAroundInterceptorClassName; + } + + /** + * Intercept the target static method. + * + * @param clazz target class + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target static method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public Object intercept(@Origin Class clazz, @AllArguments Object[] allArguments, @Origin Method method, + @SuperCall Callable zuper) throws Throwable { + StaticMethodsAroundInterceptorV2 interceptor = InterceptorInstanceLoader.load(staticMethodsAroundInterceptorClassName, + clazz.getClassLoader()); + + MethodInvocationContext context = new MethodInvocationContext(); + try { + interceptor.beforeMethod(clazz, method, allArguments, method.getParameterTypes(), context); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before static method[{}] intercept failure", clazz, method.getName()); + } + + Object ret = null; + try { + if (!context.isContinue()) { + ret = context._ret(); + } else { + ret = zuper.call(); + } + } catch (Throwable t) { + try { + interceptor.handleMethodException(clazz, method, allArguments, method.getParameterTypes(), t, context); + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle static method[{}] exception failure", clazz, method.getName(), t2.getMessage()); + } + throw t; + } finally { + try { + ret = interceptor.afterMethod(clazz, method, allArguments, method.getParameterTypes(), ret, context); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after static method[{}] intercept failure:{}", clazz, method.getName(), t.getMessage()); + } + } + return ret; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/StaticMethodsInterV2WithOverrideArgs.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/StaticMethodsInterV2WithOverrideArgs.java new file mode 100644 index 00000000..c9d1e6c8 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/enhance/v2/StaticMethodsInterV2WithOverrideArgs.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.enhance.v2; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.interceptor.enhance.OverrideCallable; +import com.example.agent.core.plugin.loader.InterceptorInstanceLoader; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Morph; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; + +import java.lang.reflect.Method; + +/** + * The actual byte-buddy's interceptor to intercept class instance methods. In this class, it provides a bridge between + * byte-buddy and sky-walking plugin. + */ +public class StaticMethodsInterV2WithOverrideArgs { + + private static final ILog LOGGER = LogManager.getLogger(StaticMethodsInterV2WithOverrideArgs.class); + + /** + * A class full name, and instanceof {@link StaticMethodsAroundInterceptorV2} This name should only stay in {@link + * String}, the real {@link Class} type will trigger classloader failure. If you want to know more, please check on + * books about Classloader or Classloader appointment mechanism. + */ + private String staticMethodsAroundInterceptorClassName; + + /** + * Set the name of {@link StaticMethodsInterV2WithOverrideArgs#staticMethodsAroundInterceptorClassName} + * + * @param staticMethodsAroundInterceptorClassName class full name. + */ + public StaticMethodsInterV2WithOverrideArgs(String staticMethodsAroundInterceptorClassName) { + this.staticMethodsAroundInterceptorClassName = staticMethodsAroundInterceptorClassName; + } + + /** + * Intercept the target static method. + * + * @param clazz target class + * @param allArguments all method arguments + * @param method method description. + * @param zuper the origin call ref. + * @return the return value of target static method. + * @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a + * bug, if anything triggers this condition ). + */ + @RuntimeType + public Object intercept(@Origin Class clazz, @AllArguments Object[] allArguments, @Origin Method method, + @Morph OverrideCallable zuper) throws Throwable { + StaticMethodsAroundInterceptorV2 interceptor = InterceptorInstanceLoader.load(staticMethodsAroundInterceptorClassName, + clazz.getClassLoader()); + + MethodInvocationContext context = new MethodInvocationContext(); + try { + interceptor.beforeMethod(clazz, method, allArguments, method.getParameterTypes(), context); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] before static method[{}] intercept failure", clazz, method.getName()); + } + + Object ret = null; + try { + if (!context.isContinue()) { + ret = context._ret(); + } else { + ret = zuper.call(allArguments); + } + } catch (Throwable t) { + try { + interceptor.handleMethodException(clazz, method, allArguments, method.getParameterTypes(), t, context); + } catch (Throwable t2) { + LOGGER.error(t2, "class[{}] handle static method[{}] exception failure", clazz, method.getName(), t2.getMessage()); + } + throw t; + } finally { + try { + ret = interceptor.afterMethod(clazz, method, allArguments, method.getParameterTypes(), ret, context); + } catch (Throwable t) { + LOGGER.error(t, "class[{}] after static method[{}] intercept failure:{}", clazz, method.getName(), t.getMessage()); + } + } + return ret; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/v2/ConstructorInterceptV2Point.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/v2/ConstructorInterceptV2Point.java new file mode 100644 index 00000000..6707fe0b --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/v2/ConstructorInterceptV2Point.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.v2; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public interface ConstructorInterceptV2Point { + + /** + * Constructor matcher + * + * @return matcher instance. + */ + ElementMatcher getConstructorMatcher(); + + /** + * @return represents a class name, the class instance must be a instance of {@link + * com.example.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor} + */ + String getConstructorInterceptorV2(); + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/v2/DeclaredInstanceMethodsInterceptV2Point.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/v2/DeclaredInstanceMethodsInterceptV2Point.java new file mode 100644 index 00000000..fed75318 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/v2/DeclaredInstanceMethodsInterceptV2Point.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.v2; + +/** + * this interface for those who only want to enhance declared method in case of some unexpected issue, such as spring + * controller + */ +public interface DeclaredInstanceMethodsInterceptV2Point extends InstanceMethodsInterceptV2Point { +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/v2/InstanceMethodsInterceptV2Point.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/v2/InstanceMethodsInterceptV2Point.java new file mode 100644 index 00000000..2fd473d9 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/v2/InstanceMethodsInterceptV2Point.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.v2; + +import com.example.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * One of the three "Intercept Point". "Intercept Point" is a definition about where and how intercept happens. In this + * "Intercept Point", the definition targets class's instance methods, and the interceptor. + *

+ * ref to two others: {@link ConstructorInterceptPoint} and {@link StaticMethodsInterceptV2Point} + *

+ */ +public interface InstanceMethodsInterceptV2Point { + + /** + * class instance methods matcher. + * + * @return methods matcher + */ + ElementMatcher getMethodsMatcher(); + + /** + * @return represents a class name, the class instance must instanceof InstanceMethodsAroundInterceptorV2. + */ + String getMethodsInterceptorV2(); + + boolean isOverrideArgs(); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/v2/StaticMethodsInterceptV2Point.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/v2/StaticMethodsInterceptV2Point.java new file mode 100644 index 00000000..bcff4221 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/interceptor/v2/StaticMethodsInterceptV2Point.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.interceptor.v2; + +import com.example.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * One of the three "Intercept Point". "Intercept Point" is a definition about where and how intercept happens. In this + * "Intercept Point", the definition targets class's static methods, and the interceptor. + *

+ * ref to two others: {@link ConstructorInterceptPoint} and {@link InstanceMethodsInterceptV2Point} + *

+ */ +public interface StaticMethodsInterceptV2Point { + + /** + * static methods matcher. + * + * @return matcher instance. + */ + ElementMatcher getMethodsMatcher(); + + /** + * @return represents a class name, the class instance must instanceof StaticMethodsAroundInterceptorV2. + */ + String getMethodsInterceptorV2(); + + boolean isOverrideArgs(); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/jdk9module/JDK9ModuleExporter.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/jdk9module/JDK9ModuleExporter.java new file mode 100644 index 00000000..7d7d87b4 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/jdk9module/JDK9ModuleExporter.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.jdk9module; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.ByteBuddyCoreClasses; +import net.bytebuddy.agent.builder.AgentBuilder; + +import java.lang.instrument.Instrumentation; +import java.util.ArrayList; +import java.util.List; + +/** + * Since JDK 9, module concept has been introduced. By supporting that, agent core needs to open the read edge + */ +public class JDK9ModuleExporter { + + private static final ILog LOGGER = LogManager.getLogger(JDK9ModuleExporter.class); + + private static final String[] HIGH_PRIORITY_CLASSES = { + "com.example.agent.core.plugin.interceptor.enhance.EnhancedInstance", + "com.example.agent.core.plugin.interceptor.enhance.MethodInterceptResult", + "com.example.agent.core.plugin.interceptor.enhance.OverrideCallable", + "com.example.agent.core.plugin.interceptor.enhance.ConstructorInter", + "com.example.agent.core.plugin.interceptor.enhance.InstMethodsInter", + "com.example.agent.core.plugin.interceptor.enhance.InstMethodsInterWithOverrideArgs", + "com.example.agent.core.plugin.interceptor.enhance.StaticMethodsInter", + "com.example.agent.core.plugin.interceptor.enhance.StaticMethodsInterWithOverrideArgs", + }; + + /** + * Assures that all modules of the supplied types are read by the module of any instrumented type. JDK Module system + * was introduced since JDK9. + *

+ * The following codes work only JDK Module system exist. + */ + public static AgentBuilder openReadEdge(Instrumentation instrumentation, AgentBuilder agentBuilder, + EdgeClasses classes) { + for (String className : classes.classes) { + try { + agentBuilder = agentBuilder.assureReadEdgeFromAndTo(instrumentation, Class.forName(className)); + } catch (ClassNotFoundException e) { + throw new UnsupportedOperationException("Fail to open read edge for class " + className + " to public access in JDK9+", e); + } + } + for (String className : HIGH_PRIORITY_CLASSES) { + try { + agentBuilder = agentBuilder.assureReadEdgeFromAndTo(instrumentation, Class.forName(className)); + } catch (ClassNotFoundException e) { + throw new UnsupportedOperationException("Fail to open read edge for class " + className + " to public access in JDK9+", e); + } + } + + return agentBuilder; + } + + public static class EdgeClasses { + + private List classes = new ArrayList(); + + public EdgeClasses() { + for (String className : ByteBuddyCoreClasses.CLASSES) { + add(className); + } + } + + public void add(String className) { + if (!classes.contains(className)) { + classes.add(className); + } + } + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/loader/AgentClassLoader.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/loader/AgentClassLoader.java new file mode 100644 index 00000000..120aefc5 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/loader/AgentClassLoader.java @@ -0,0 +1,225 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.loader; + +import com.example.agent.core.boot.AgentPackageNotFoundException; +import com.example.agent.core.boot.AgentPackagePath; +import com.example.agent.core.boot.PluginConfig; +import com.example.agent.core.boot.SpringBootConfigInitializer; +import com.example.agent.core.boot.SpringBootConfigNode; +import com.example.agent.core.conf.Config; +import com.example.agent.core.conf.SnifferConfigInitializer; +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import com.example.agent.core.plugin.PluginBootstrap; +import lombok.RequiredArgsConstructor; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.locks.ReentrantLock; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * The AgentClassLoader represents a classloader, which is in charge of finding plugins and interceptors. + */ +public class AgentClassLoader extends ClassLoader { + + static { + /* + * Try to solve the classloader dead lock. See https://github.com/apache/skywalking/pull/2016 + */ + registerAsParallelCapable(); + } + + private static final ILog LOGGER = LogManager.getLogger(AgentClassLoader.class); + /** + * The default class loader for the agent. + */ + private static AgentClassLoader DEFAULT_LOADER; + + private List classpath; + private List allJars; + private ReentrantLock jarScanLock = new ReentrantLock(); + + public static AgentClassLoader getDefault() { + return DEFAULT_LOADER; + } + + /** + * Init the default class loader. + * + * @throws AgentPackageNotFoundException if agent package is not found. + */ + public static void initDefaultLoader() throws AgentPackageNotFoundException { + if (DEFAULT_LOADER == null) { + synchronized (AgentClassLoader.class) { + if (DEFAULT_LOADER == null) { + DEFAULT_LOADER = new AgentClassLoader(PluginBootstrap.class.getClassLoader()); + } + } + } + } + + public AgentClassLoader(ClassLoader parent) throws AgentPackageNotFoundException { + super(parent); + File agentDictionary = AgentPackagePath.getPath(); + classpath = new LinkedList<>(); + Config.Plugin.MOUNT.forEach(mountFolder -> classpath.add(new File(agentDictionary, mountFolder))); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + List allJars = getAllJars(); + String path = name.replace('.', '/').concat(".class"); + for (Jar jar : allJars) { + JarEntry entry = jar.jarFile.getJarEntry(path); + if (entry == null) { + continue; + } + try { + URL classFileUrl = new URL("jar:file:" + jar.sourceFile.getAbsolutePath() + "!/" + path); + byte[] data; + try ( + final BufferedInputStream is = new BufferedInputStream( + classFileUrl.openStream()); + final ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + int ch; + while ((ch = is.read()) != -1) { + baos.write(ch); + } + data = baos.toByteArray(); + } + return processLoadedClass(defineClass(name, data, 0, data.length)); + } catch (IOException e) { + LOGGER.error(e, "find class fail."); + } + } + throw new ClassNotFoundException("Can't find " + name); + } + + @Override + protected URL findResource(String name) { + List allJars = getAllJars(); + for (Jar jar : allJars) { + JarEntry entry = jar.jarFile.getJarEntry(name); + if (entry != null) { + try { + return new URL("jar:file:" + jar.sourceFile.getAbsolutePath() + "!/" + name); + } catch (MalformedURLException ignored) { + } + } + } + return null; + } + + @Override + protected Enumeration findResources(String name) throws IOException { + List allResources = new LinkedList<>(); + List allJars = getAllJars(); + for (Jar jar : allJars) { + JarEntry entry = jar.jarFile.getJarEntry(name); + if (entry != null) { + allResources.add(new URL("jar:file:" + jar.sourceFile.getAbsolutePath() + "!/" + name)); + } + } + + final Iterator iterator = allResources.iterator(); + return new Enumeration() { + + @Override + public boolean hasMoreElements() { + return iterator.hasNext(); + } + + @Override + public URL nextElement() { + return iterator.next(); + } + }; + } + + private Class processLoadedClass(Class loadedClass) { + final PluginConfig pluginConfig = loadedClass.getAnnotation(PluginConfig.class); + if (pluginConfig != null) { + // Set up the plugin config when loaded by class loader at the first time. + // Agent class loader just loaded limited classes in the plugin jar(s), so the cost of this + // isAssignableFrom would be also very limited. + SnifferConfigInitializer.initializeConfig(pluginConfig.root()); + } + + final SpringBootConfigNode springBootConfig = loadedClass.getAnnotation(SpringBootConfigNode.class); + if (springBootConfig != null) { + // Set up the plugin config when loaded by spring environment is prepared, just scan in here. + // Agent class loader just loaded limited classes in the plugin jar(s), so the cost of this + // isAssignableFrom would be also very limited. + SpringBootConfigInitializer.initializeConfig(springBootConfig); + } + return loadedClass; + } + + private List getAllJars() { + if (allJars == null) { + jarScanLock.lock(); + try { + if (allJars == null) { + allJars = doGetJars(); + } + } finally { + jarScanLock.unlock(); + } + } + + return allJars; + } + + private LinkedList doGetJars() { + LinkedList jars = new LinkedList<>(); + for (File path : classpath) { + if (path.exists() && path.isDirectory()) { + String[] jarFileNames = path.list((dir, name) -> name.endsWith(".jar")); + for (String fileName : jarFileNames) { + try { + File file = new File(path, fileName); + Jar jar = new Jar(new JarFile(file), file); + jars.add(jar); + LOGGER.info("{} loaded.", file.toString()); + } catch (IOException e) { + LOGGER.error(e, "{} jar file can't be resolved", fileName); + } + } + } + } + return jars; + } + + @RequiredArgsConstructor + private static class Jar { + + private final JarFile jarFile; + private final File sourceFile; + } +} \ No newline at end of file diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/loader/InstrumentationLoader.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/loader/InstrumentationLoader.java new file mode 100644 index 00000000..0f2ffb09 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/loader/InstrumentationLoader.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.loader; + +import com.example.agent.core.plugin.AbstractClassEnhancePluginDefine; + +import java.util.List; + +/** + * the spi of the InstrumentationLoader. + */ + +public interface InstrumentationLoader { + + List load(AgentClassLoader classLoader); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/loader/InterceptorInstanceLoader.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/loader/InterceptorInstanceLoader.java new file mode 100644 index 00000000..06db75a7 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/loader/InterceptorInstanceLoader.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.loader; + +import com.example.agent.core.boot.AgentPackageNotFoundException; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; + +/** + * The InterceptorInstanceLoader is a classes finder and container. + *

+ * This is a very important class in sky-walking's auto-instrumentation mechanism. If you want to fully understand why + * need this, and how it works, you need have knowledge about Classloader appointment mechanism. + *

+ */ +public class InterceptorInstanceLoader { + + private static ConcurrentHashMap INSTANCE_CACHE = new ConcurrentHashMap(); + private static ReentrantLock INSTANCE_LOAD_LOCK = new ReentrantLock(); + private static Map EXTEND_PLUGIN_CLASSLOADERS = new HashMap(); + + /** + * Load an instance of interceptor, and keep it singleton. Create {@link AgentClassLoader} for each + * targetClassLoader, as an extend classloader. It can load interceptor classes from plugins, activations folders. + * + * @param className the interceptor class, which is expected to be found + * @param targetClassLoader the class loader for current application context + * @param expected type + * @return the type reference. + */ + public static T load(String className, + ClassLoader targetClassLoader) throws IllegalAccessException, InstantiationException, ClassNotFoundException, AgentPackageNotFoundException { + if (targetClassLoader == null) { + targetClassLoader = InterceptorInstanceLoader.class.getClassLoader(); + } + String instanceKey = className + "_OF_" + targetClassLoader.getClass() + .getName() + "@" + + Integer.toHexString(targetClassLoader + .hashCode()); + Object inst = INSTANCE_CACHE.get(instanceKey); + if (inst == null) { + INSTANCE_LOAD_LOCK.lock(); + ClassLoader pluginLoader; + try { + pluginLoader = EXTEND_PLUGIN_CLASSLOADERS.get(targetClassLoader); + if (pluginLoader == null) { + pluginLoader = new AgentClassLoader(targetClassLoader); + EXTEND_PLUGIN_CLASSLOADERS.put(targetClassLoader, pluginLoader); + } + } finally { + INSTANCE_LOAD_LOCK.unlock(); + } + inst = Class.forName(className, true, pluginLoader).newInstance(); + if (inst != null) { + INSTANCE_CACHE.put(instanceKey, inst); + } + } + + return (T) inst; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/ClassAnnotationMatch.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/ClassAnnotationMatch.java new file mode 100644 index 00000000..d4829588 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/ClassAnnotationMatch.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.match; + +import net.bytebuddy.description.annotation.AnnotationDescription; +import net.bytebuddy.description.annotation.AnnotationList; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; +import static net.bytebuddy.matcher.ElementMatchers.isInterface; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.not; + +/** + * Match the class by the given annotations in class. + */ +public class ClassAnnotationMatch implements IndirectMatch { + + private String[] annotations; + + private ClassAnnotationMatch(String[] annotations) { + if (annotations == null || annotations.length == 0) { + throw new IllegalArgumentException("annotations is null"); + } + this.annotations = annotations; + } + + @Override + public ElementMatcher.Junction buildJunction() { + ElementMatcher.Junction junction = null; + for (String annotation : annotations) { + if (junction == null) { + junction = buildEachAnnotation(annotation); + } else { + junction = junction.and(buildEachAnnotation(annotation)); + } + } + junction = junction.and(not(isInterface())); + return junction; + } + + @Override + public boolean isMatch(TypeDescription typeDescription) { + List annotationList = new ArrayList(Arrays.asList(annotations)); + AnnotationList declaredAnnotations = typeDescription.getDeclaredAnnotations(); + for (AnnotationDescription annotation : declaredAnnotations) { + annotationList.remove(annotation.getAnnotationType().getActualName()); + } + return annotationList.isEmpty(); + } + + private ElementMatcher.Junction buildEachAnnotation(String annotationName) { + return isAnnotatedWith(named(annotationName)); + } + + public static ClassAnnotationMatch byClassAnnotationMatch(String... annotations) { + return new ClassAnnotationMatch(annotations); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/ClassMatch.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/ClassMatch.java new file mode 100644 index 00000000..839a2113 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/ClassMatch.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.match; + +public interface ClassMatch { +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/HierarchyMatch.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/HierarchyMatch.java new file mode 100644 index 00000000..ed990a22 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/HierarchyMatch.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.match; + +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.description.type.TypeList; +import net.bytebuddy.matcher.ElementMatcher; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static net.bytebuddy.matcher.ElementMatchers.hasSuperType; +import static net.bytebuddy.matcher.ElementMatchers.isInterface; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.not; + +/** + * Match the class by the given super class or interfaces. + */ +public class HierarchyMatch implements IndirectMatch { + + private String[] parentTypes; + + private HierarchyMatch(String[] parentTypes) { + if (parentTypes == null || parentTypes.length == 0) { + throw new IllegalArgumentException("parentTypes is null"); + } + this.parentTypes = parentTypes; + } + + @Override + public ElementMatcher.Junction buildJunction() { + ElementMatcher.Junction junction = null; + for (String superTypeName : parentTypes) { + if (junction == null) { + junction = buildSuperClassMatcher(superTypeName); + } else { + junction = junction.and(buildSuperClassMatcher(superTypeName)); + } + } + junction = junction.and(not(isInterface())); + return junction; + } + + private ElementMatcher.Junction buildSuperClassMatcher(String superTypeName) { + return hasSuperType(named(superTypeName)); + } + + @Override + public boolean isMatch(TypeDescription typeDescription) { + List parentTypes = new ArrayList(Arrays.asList(this.parentTypes)); + + TypeList.Generic implInterfaces = typeDescription.getInterfaces(); + for (TypeDescription.Generic implInterface : implInterfaces) { + matchHierarchyClass(implInterface, parentTypes); + } + + if (typeDescription.getSuperClass() != null) { + matchHierarchyClass(typeDescription.getSuperClass(), parentTypes); + } + + return parentTypes.size() == 0; + + } + + private void matchHierarchyClass(TypeDescription.Generic clazz, List parentTypes) { + parentTypes.remove(clazz.asRawType().getTypeName()); + if (parentTypes.size() == 0) { + return; + } + + for (TypeDescription.Generic generic : clazz.getInterfaces()) { + matchHierarchyClass(generic, parentTypes); + } + + TypeDescription.Generic superClazz = clazz.getSuperClass(); + if (superClazz != null && !clazz.getTypeName().equals("java.lang.Object")) { + matchHierarchyClass(superClazz, parentTypes); + } + + } + + public static IndirectMatch byHierarchyMatch(String... parentTypes) { + return new HierarchyMatch(parentTypes); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/IndirectMatch.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/IndirectMatch.java new file mode 100644 index 00000000..086d848b --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/IndirectMatch.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.match; + +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * All implementations can't direct match the class like {@link NameMatch} did. + */ +public interface IndirectMatch extends ClassMatch { + + ElementMatcher.Junction buildJunction(); + + boolean isMatch(TypeDescription typeDescription); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/MethodAnnotationMatch.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/MethodAnnotationMatch.java new file mode 100644 index 00000000..d8a5c99f --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/MethodAnnotationMatch.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.match; + +import net.bytebuddy.description.annotation.AnnotationDescription; +import net.bytebuddy.description.annotation.AnnotationList; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.ElementMatchers; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static net.bytebuddy.matcher.ElementMatchers.declaresMethod; +import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; +import static net.bytebuddy.matcher.ElementMatchers.isInterface; +import static net.bytebuddy.matcher.ElementMatchers.named; + +/** + * Match the class, which has methods with the certain annotations. This is a very complex match. + */ +public class MethodAnnotationMatch implements IndirectMatch { + + private String[] annotations; + + private MethodAnnotationMatch(String[] annotations) { + if (annotations == null || annotations.length == 0) { + throw new IllegalArgumentException("annotations is null"); + } + this.annotations = annotations; + } + + @Override + public ElementMatcher.Junction buildJunction() { + ElementMatcher.Junction junction = null; + for (String annotation : annotations) { + if (junction == null) { + junction = buildEachAnnotation(annotation); + } else { + junction = junction.and(buildEachAnnotation(annotation)); + } + } + junction = declaresMethod(junction).and(ElementMatchers.not(isInterface())); + return junction; + } + + @Override + public boolean isMatch(TypeDescription typeDescription) { + for (MethodDescription.InDefinedShape methodDescription : typeDescription.getDeclaredMethods()) { + List annotationList = new ArrayList(Arrays.asList(annotations)); + + AnnotationList declaredAnnotations = methodDescription.getDeclaredAnnotations(); + for (AnnotationDescription annotation : declaredAnnotations) { + annotationList.remove(annotation.getAnnotationType().getActualName()); + } + if (annotationList.isEmpty()) { + return true; + } + } + + return false; + } + + private ElementMatcher.Junction buildEachAnnotation(String annotationName) { + return isAnnotatedWith(named(annotationName)); + } + + public static IndirectMatch byMethodAnnotationMatch(String... annotations) { + return new MethodAnnotationMatch(annotations); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/MethodInheritanceAnnotationMatcher.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/MethodInheritanceAnnotationMatcher.java new file mode 100644 index 00000000..0ff4bc78 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/MethodInheritanceAnnotationMatcher.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.match; + +import net.bytebuddy.build.HashCodeAndEqualsPlugin; +import net.bytebuddy.description.annotation.AnnotationList; +import net.bytebuddy.description.annotation.AnnotationSource; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.method.MethodList; +import net.bytebuddy.description.method.ParameterList; +import net.bytebuddy.description.type.TypeDefinition; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.description.type.TypeList; +import net.bytebuddy.matcher.CollectionItemMatcher; +import net.bytebuddy.matcher.ElementMatcher; + +import java.util.Objects; + +import static net.bytebuddy.matcher.ElementMatchers.annotationType; + +/** + * Matching used to match method annotations, Can match annotations on interface methods + */ +@HashCodeAndEqualsPlugin.Enhance +public class MethodInheritanceAnnotationMatcher extends ElementMatcher.Junction.AbstractBase { + + /** + * The matcher to be applied to the provided annotation list. + */ + private final ElementMatcher matcher; + + /** + * Creates a new matcher for the annotations of an annotated element. + * + * @param matcher The matcher to be applied to the provided annotation list. + */ + public MethodInheritanceAnnotationMatcher(ElementMatcher matcher) { + this.matcher = matcher; + } + + @Override + public boolean matches(T target) { + if (matcher.matches(target.getDeclaredAnnotations())) { + return true; + } + String name = target.getName(); + ParameterList parameters = target.getParameters(); + + TypeDefinition declaringType = target.getDeclaringType(); + return recursiveMatches(declaringType, name, parameters); + } + + private boolean recursiveMatches(TypeDefinition typeDefinition, String methodName, ParameterList parameters) { + TypeList.Generic interfaces = typeDefinition.getInterfaces(); + for (TypeDescription.Generic implInterface : interfaces) { + if (recursiveMatches(implInterface, methodName, parameters)) { + return true; + } + MethodList declaredMethods = implInterface.getDeclaredMethods(); + for (MethodDescription declaredMethod : declaredMethods) { + if (Objects.equals(declaredMethod.getName(), methodName) && parameterEquals(parameters, declaredMethod.getParameters())) { + return matcher.matches(declaredMethod.getDeclaredAnnotations()); + } + } + } + return false; + } + + private boolean parameterEquals(ParameterList source, ParameterList impl) { + if (source.size() != impl.size()) { + return false; + } + for (int i = 0; i < source.size(); i++) { + if (!Objects.equals(source.get(i).getType(), impl.get(i).getType())) { + return false; + } + } + return true; + } + + public static Junction byMethodInheritanceAnnotationMatcher( + ElementMatcher matcher) { + return new MethodInheritanceAnnotationMatcher(new CollectionItemMatcher<>(annotationType(matcher))); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/MultiClassNameMatch.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/MultiClassNameMatch.java new file mode 100644 index 00000000..7bcf3fac --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/MultiClassNameMatch.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.match; + +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +import java.util.Arrays; +import java.util.List; + +import static net.bytebuddy.matcher.ElementMatchers.named; + +/** + * Match class with a given set of classes. + */ +public class MultiClassNameMatch implements IndirectMatch { + + private List matchClassNames; + + private MultiClassNameMatch(String[] classNames) { + if (classNames == null || classNames.length == 0) { + throw new IllegalArgumentException("match class names is null"); + } + this.matchClassNames = Arrays.asList(classNames); + } + + @Override + public ElementMatcher.Junction buildJunction() { + ElementMatcher.Junction junction = null; + for (String name : matchClassNames) { + if (junction == null) { + junction = named(name); + } else { + junction = junction.or(named(name)); + } + } + return junction; + } + + @Override + public boolean isMatch(TypeDescription typeDescription) { + return matchClassNames.contains(typeDescription.getTypeName()); + } + + public static IndirectMatch byMultiClassMatch(String... classNames) { + return new MultiClassNameMatch(classNames); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/NameMatch.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/NameMatch.java new file mode 100644 index 00000000..95dc4b2e --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/NameMatch.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.match; + +/** + * Match the class with an explicit class name. + */ +public class NameMatch implements ClassMatch { + + private String className; + + private NameMatch(String className) { + this.className = className; + } + + public String getClassName() { + return className; + } + + public static NameMatch byName(String className) { + return new NameMatch(className); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/PrefixMatch.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/PrefixMatch.java new file mode 100644 index 00000000..aae7fab5 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/PrefixMatch.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.match; + +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.ElementMatchers; + +/** + * Match classes by any one of the given {@link #prefixes} + */ +@SuppressWarnings("rawtypes") +public class PrefixMatch implements IndirectMatch { + + private String[] prefixes; + + private PrefixMatch(String... prefixes) { + if (prefixes == null || prefixes.length == 0) { + throw new IllegalArgumentException("prefixes argument is null or empty"); + } + this.prefixes = prefixes; + } + + @Override + public ElementMatcher.Junction buildJunction() { + ElementMatcher.Junction junction = null; + + for (String prefix : prefixes) { + if (junction == null) { + junction = ElementMatchers.nameStartsWith(prefix); + } else { + junction = junction.or(ElementMatchers.nameStartsWith(prefix)); + } + } + + return junction; + } + + @Override + public boolean isMatch(TypeDescription typeDescription) { + for (final String prefix : prefixes) { + if (typeDescription.getName().startsWith(prefix)) { + return true; + } + } + return false; + } + + public static PrefixMatch nameStartsWith(final String... prefixes) { + return new PrefixMatch(prefixes); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/ProtectiveShieldMatcher.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/ProtectiveShieldMatcher.java new file mode 100644 index 00000000..8c8b47df --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/ProtectiveShieldMatcher.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.match; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * In some cases, some frameworks and libraries use some binary codes tech too. From the community feedback, some of + * them have compatible issues with byte-buddy core, which trigger "Can't resolve type description" exception. + *

+ * So I build this protective shield by a nested matcher. When the origin matcher(s) can't resolve the type, the + * cook-async agent ignores this types. + *

+ * Notice: this ignore mechanism may miss some instrumentations, but at most cases, it's same. If missing happens, + * please pay attention to the WARNING logs. + */ +public class ProtectiveShieldMatcher extends ElementMatcher.Junction.AbstractBase { + + private static final ILog LOGGER = LogManager.getLogger(ProtectiveShieldMatcher.class); + + private final ElementMatcher matcher; + + public ProtectiveShieldMatcher(ElementMatcher matcher) { + this.matcher = matcher; + } + + @Override + public boolean matches(T target) { + try { + return this.matcher.matches(target); + } catch (Throwable t) { + if (LOGGER.isDebugEnable()) { + LOGGER.debug(t, "Byte-buddy occurs exception when match type."); + } + return false; + } + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/RegexMatch.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/RegexMatch.java new file mode 100644 index 00000000..06557847 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/RegexMatch.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.match; + +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +import static net.bytebuddy.matcher.ElementMatchers.nameMatches; + +/** + * Match the class by given class name regex expression. + */ +public class RegexMatch implements IndirectMatch { + + private String[] regexExpressions; + + private RegexMatch(String... regexExpressions) { + if (regexExpressions == null || regexExpressions.length == 0) { + throw new IllegalArgumentException("annotations is null"); + } + this.regexExpressions = regexExpressions; + } + + @Override + public ElementMatcher.Junction buildJunction() { + ElementMatcher.Junction regexJunction = null; + for (String regexExpression : regexExpressions) { + if (regexJunction == null) { + regexJunction = nameMatches(regexExpression); + } else { + regexJunction = regexJunction.or(nameMatches(regexExpression)); + } + } + return regexJunction; + } + + @Override + public boolean isMatch(TypeDescription typeDescription) { + boolean isMatch = false; + for (String matchExpression : regexExpressions) { + isMatch = typeDescription.getTypeName().matches(matchExpression); + if (isMatch) { + break; + } + } + return isMatch; + } + + public static RegexMatch byRegexMatch(String... regexExpressions) { + return new RegexMatch(regexExpressions); + } +} \ No newline at end of file diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/logical/LogicalAndMatch.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/logical/LogicalAndMatch.java new file mode 100644 index 00000000..36fbf1c1 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/logical/LogicalAndMatch.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.match.logical; + +import com.example.agent.core.plugin.match.IndirectMatch; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * Match classes by multiple criteria with AND conjunction + */ +public class LogicalAndMatch implements IndirectMatch { + + private final IndirectMatch[] indirectMatches; + + /** + * Don't instantiate this class directly, use {@link LogicalMatchOperation} instead + * + * @param indirectMatches the matching criteria to conjunct with AND + */ + LogicalAndMatch(final IndirectMatch... indirectMatches) { + this.indirectMatches = indirectMatches; + } + + @Override + public ElementMatcher.Junction buildJunction() { + ElementMatcher.Junction junction = null; + + for (final IndirectMatch indirectMatch : indirectMatches) { + if (junction == null) { + junction = indirectMatch.buildJunction(); + } else { + junction = junction.and(indirectMatch.buildJunction()); + } + } + + return junction; + } + + @Override + public boolean isMatch(final TypeDescription typeDescription) { + for (final IndirectMatch indirectMatch : indirectMatches) { + if (!indirectMatch.isMatch(typeDescription)) { + return false; + } + } + + return true; + } + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/logical/LogicalMatchOperation.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/logical/LogicalMatchOperation.java new file mode 100644 index 00000000..7f7c50ec --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/logical/LogicalMatchOperation.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.match.logical; + +import com.example.agent.core.plugin.match.IndirectMatch; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.NegatingMatcher; + +/** + * Util class to help to construct logical operations on {@link com.example.agent.core.plugin.match.ClassMatch}s + */ +public class LogicalMatchOperation { + + public static IndirectMatch and(final IndirectMatch... matches) { + return new LogicalAndMatch(matches); + } + + public static IndirectMatch or(final IndirectMatch... matches) { + return new LogicalOrMatch(matches); + } + + public static IndirectMatch not(final IndirectMatch match) { + return new IndirectMatch() { + + @Override + public ElementMatcher.Junction buildJunction() { + return new NegatingMatcher(match.buildJunction()); + } + + @Override + public boolean isMatch(final TypeDescription typeDescription) { + return !match.isMatch(typeDescription); + } + }; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/logical/LogicalOrMatch.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/logical/LogicalOrMatch.java new file mode 100644 index 00000000..b24993c8 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/plugin/match/logical/LogicalOrMatch.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.plugin.match.logical; + +import com.example.agent.core.plugin.match.IndirectMatch; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * Match classes by multiple criteria with OR conjunction + */ +public class LogicalOrMatch implements IndirectMatch { + + private final IndirectMatch[] indirectMatches; + + /** + * Don't instantiate this class directly, use {@link LogicalMatchOperation} instead + * + * @param indirectMatches the matching criteria to conjunct with OR + */ + LogicalOrMatch(final IndirectMatch... indirectMatches) { + this.indirectMatches = indirectMatches; + } + + @Override + public ElementMatcher.Junction buildJunction() { + ElementMatcher.Junction junction = null; + + for (final IndirectMatch indirectMatch : indirectMatches) { + if (junction == null) { + junction = indirectMatch.buildJunction(); + } else { + junction = junction.or(indirectMatch.buildJunction()); + } + } + + return junction; + } + + @Override + public boolean isMatch(final TypeDescription typeDescription) { + for (final IndirectMatch indirectMatch : indirectMatches) { + if (indirectMatch.isMatch(typeDescription)) { + return true; + } + } + + return false; + } + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/AgentThreadPoolConstants.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/AgentThreadPoolConstants.java new file mode 100644 index 00000000..b51fa6c9 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/AgentThreadPoolConstants.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.util; + +public interface AgentThreadPoolConstants { + + String TOMCAT_NAME_PREFIX = "namePrefix"; + String DUBBO_NAME_PREFIX = "mPrefix"; + String DUBBO_THREAD_NAME = "DubboServerHandler"; + String THREAD_POOL_NAME_DUBBO = "dubbo"; + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/CollectionUtil.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/CollectionUtil.java new file mode 100644 index 00000000..f450c2ca --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/CollectionUtil.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.util; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Some utility methods for collections. Reinvent the wheels because importing third-party libs just for some methods is + * not worthwhile in agent side + * + * @since 7.0.0 + */ +public final class CollectionUtil { + + public static String toString(final Map map) { + return map.entrySet() + .stream() + .map(entry -> entry.getKey() + "=" + Arrays.toString(entry.getValue())) + .collect(Collectors.joining("\n")); + } + + @SuppressWarnings("rawtypes") + public static boolean isEmpty(Collection collection) { + return collection == null || collection.isEmpty(); + } + + /** + * Is empty. + * + * @param map + * @return + */ + public static boolean isEmpty(Map map) { + return map == null || map.isEmpty(); + } + + /** + * Is not empty. + * + * @param map + * @return + */ + public static boolean isNotEmpty(Map map) { + return !isEmpty(map); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/ConfigInitializer.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/ConfigInitializer.java new file mode 100644 index 00000000..27cc5c1c --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/ConfigInitializer.java @@ -0,0 +1,213 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.util; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; + +/** + * Init a class's static fields by a {@link Properties}, including static fields and static inner classes. + *

+ */ +public class ConfigInitializer { + + public static void initialize(Properties properties, Class rootConfigType) throws IllegalAccessException { + initNextLevel(properties, rootConfigType, new ConfigDesc(), false); + } + + public static void initialize(Properties properties, Class rootConfigType, boolean isSpringProperties) throws IllegalAccessException { + initNextLevel(properties, rootConfigType, new ConfigDesc(), isSpringProperties); + } + + private static void initNextLevel(Properties properties, Class recentConfigType, + ConfigDesc parentDesc, boolean isSpringProperties) throws IllegalArgumentException, IllegalAccessException { + for (Field field : recentConfigType.getFields()) { + if (Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())) { + String configKey = (parentDesc + "." + (isSpringProperties ? field.getName().replace("_", "-") : field.getName())).toLowerCase(); + Class type = field.getType(); + + if (type.equals(Map.class)) { + /* + * Map config format is, config_key[map_key]=map_value Such as plugin.opgroup.resttemplate.rule[abc]=/url/path + */ + // Deduct two generic types of the map + ParameterizedType genericType = (ParameterizedType) field.getGenericType(); + Type[] argumentTypes = genericType.getActualTypeArguments(); + + Type keyType = null; + Type valueType = null; + if (argumentTypes != null && argumentTypes.length == 2) { + // Get key type and value type of the map + keyType = argumentTypes[0]; + valueType = argumentTypes[1]; + } + Map map = (Map) field.get(null); + // Set the map from config key and properties + setForMapType(configKey, map, properties, keyType, valueType); + } else { + /* + * Others typical field type + */ + String value = properties.getProperty(configKey); + // Convert the value into real type + final Length lengthDefine = field.getAnnotation(Length.class); + if (lengthDefine != null) { + if (value != null && value.length() > lengthDefine.value()) { + value = value.substring(0, lengthDefine.value()); + } + } + Object convertedValue = convertToTypicalType(type, value); + if (convertedValue != null) { + field.set(null, convertedValue); + } + } + } + } + for (Class innerConfiguration : recentConfigType.getClasses()) { + String simpleName = innerConfiguration.getSimpleName(); + String description = isSpringProperties ? simpleName.replace("_", "-") : simpleName; + parentDesc.append(description); + initNextLevel(properties, innerConfiguration, parentDesc, isSpringProperties); + parentDesc.removeLastDesc(); + } + } + + /** + * Convert string value to typical type. + * + * @param type type to convert + * @param value string value to be converted + * @return converted value or null + */ + private static Object convertToTypicalType(Type type, String value) { + if (value == null || type == null) { + return null; + } + + Object result = null; + if (String.class.equals(type)) { + result = value; + } else if (int.class.equals(type) || Integer.class.equals(type)) { + result = Integer.valueOf(value); + } else if (long.class.equals(type) || Long.class.equals(type)) { + result = Long.valueOf(value); + } else if (boolean.class.equals(type) || Boolean.class.equals(type)) { + result = Boolean.valueOf(value); + } else if (float.class.equals(type) || Float.class.equals(type)) { + result = Float.valueOf(value); + } else if (double.class.equals(type) || Double.class.equals(type)) { + result = Double.valueOf(value); + } else if (List.class.equals(type)) { + result = convert2List(value); + } else if (type instanceof Class) { + Class clazz = (Class) type; + if (clazz.isEnum()) { + result = Enum.valueOf((Class) type, value.toUpperCase()); + } + } + return result; + } + + /** + * Set map items. + * + * @param configKey config key must not be null + * @param map map to set must not be null + * @param properties properties must not be null + * @param keyType key type of the map + * @param valueType value type of the map + */ + private static void setForMapType(String configKey, Map map, Properties properties, + final Type keyType, final Type valueType) { + + Objects.requireNonNull(configKey); + Objects.requireNonNull(map); + Objects.requireNonNull(properties); + + String prefix = configKey + "["; + String suffix = "]"; + + properties.forEach((propertyKey, propertyValue) -> { + String propertyStringKey = propertyKey.toString(); + if (propertyStringKey.startsWith(prefix) && propertyStringKey.endsWith(suffix)) { + String itemKey = propertyStringKey.substring( + prefix.length(), propertyStringKey.length() - suffix.length()); + Object keyObj; + Object valueObj; + + keyObj = convertToTypicalType(keyType, itemKey); + valueObj = convertToTypicalType(valueType, propertyValue.toString()); + + if (keyObj == null) { + keyObj = itemKey; + } + + if (valueObj == null) { + valueObj = propertyValue; + } + + map.put(keyObj, valueObj); + } + }); + } + + private static List convert2List(String value) { + if (StringUtil.isEmpty(value)) { + return Collections.emptyList(); + } + List result = new LinkedList<>(); + + String[] segments = value.split(","); + for (String segment : segments) { + String trimmedSegment = segment.trim(); + if (StringUtil.isNotEmpty(trimmedSegment)) { + result.add(trimmedSegment); + } + } + return result; + } + +} + +class ConfigDesc { + + private LinkedList descs = new LinkedList<>(); + + void append(String currentDesc) { + if (StringUtil.isNotEmpty(currentDesc)) { + descs.addLast(currentDesc); + } + } + + void removeLastDesc() { + descs.removeLast(); + } + + @Override + public String toString() { + return String.join(".", descs); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/CustomizeExpression.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/CustomizeExpression.java new file mode 100644 index 00000000..ee8408f4 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/CustomizeExpression.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.util; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * a simple parsing expression + */ + +public class CustomizeExpression { + + private static final ILog LOGGER = LogManager.getLogger(CustomizeExpression.class); + + public static Map evaluationContext(Object[] allArguments) { + Map context = new HashMap<>(); + if (allArguments == null) { + return context; + } + for (int i = 0; i < allArguments.length; i++) { + context.put("arg[" + i + "]", allArguments[i]); + } + return context; + } + + public static Map evaluationReturnContext(Object ret) { + Map context = new HashMap<>(); + context.put("returnedObj", ret); + return context; + } + + public static String parseExpression(String expression, Map context) { + try { + String[] es = expression.split("\\."); + Object o = context.get(es[0]); + return o == null ? "null" : String.valueOf(parse(es, o, 0)); + } catch (Exception e) { + LOGGER.debug("parse expression error, expression is {}, exception is {}", expression, e.getMessage()); + } + return "null"; + } + + private static Object parse(String[] expressions, Object o, int i) { + int next = i + 1; + if (next == expressions.length) { + return o; + } else { + o = parse0(expressions[next], o); + return o == null ? "null" : parse(expressions, o, next); + } + } + + private static Object parse0(String expression, Object o) { + if (o instanceof Map) { + return matcherMap(expression, o); + } else if (o instanceof List) { + return matcherList(expression, o); + } else if (o.getClass().isArray()) { + return matcherArray(expression, o); + } else { + return matcherDefault(expression, o); + } + } + + private static Object matcherMap(String expression, Object o) { + String key = expression.replace("['", "").replace("']", ""); + return ((Map) o).get(key); + } + + private static Object matcherList(String expression, Object o) { + int index = Integer.parseInt(expression.replace("[", "").replace("]", "")); + List l = (List) o; + return l != null && l.size() > index ? l.get(index) : null; + } + + private static Object matcherArray(String expression, Object o) { + int index = Integer.parseInt(expression.replace("[", "").replace("]", "")); + return o != null && Array.getLength(o) > index ? Array.get(o, index) : null; + } + + private static Object matcherDefault(String expression, Object o) { + try { + if (expression.contains("()")) { + Method m = o.getClass().getMethod(expression.replace("()", "")); + m.setAccessible(true); + return m.invoke(o); + } else { + Field f = o.getClass().getDeclaredField(expression); + f.setAccessible(true); + return f.get(o); + } + } catch (Exception e) { + LOGGER.debug("matcher default error, expression is {}, object is {}, expression is {}", expression, o, e.getMessage()); + } + return null; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/ExecutorNameUtil.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/ExecutorNameUtil.java new file mode 100644 index 00000000..217f193a --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/ExecutorNameUtil.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.util; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; + +import java.lang.reflect.Field; + +public class ExecutorNameUtil { + + private static final ILog LOGGER = LogManager.getLogger(ExecutorNameUtil.class); + + public static boolean isTomcatExecutor(Object threadFactory) { + try { + if ("org.apache.tomcat.util.threads.TaskThreadFactory".equals(threadFactory.getClass().getName())) { + Field namePrefixField = threadFactory.getClass().getDeclaredField(AgentThreadPoolConstants.TOMCAT_NAME_PREFIX); + namePrefixField.setAccessible(true); + String namePrefix = (String) namePrefixField.get(threadFactory); + if (RegexUtil.isTomcatNameMatch(namePrefix)) { + return true; + } + } + } catch (Throwable t) { + LOGGER.error("Fail to put tomcat executor", t); + } + return false; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/FileUtils.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/FileUtils.java new file mode 100644 index 00000000..d69c47a8 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/FileUtils.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.util; + +import java.io.File; +import java.nio.file.Files; + +public class FileUtils { + + /** + * delete directories and files recursively + * + * @param dir directory to delete + */ + public static void deleteDirectory(File dir) { + File[] files = dir.listFiles(); + if (files != null) { + for (File file : files) { + if (!Files.isSymbolicLink(file.toPath())) { + if (file.isDirectory()) { + deleteDirectory(file); + } else { + file.delete(); + } + } else { + file.delete(); + } + } + } + dir.delete(); + } + + public static void deleteDirectoryOnExit(File dir) { + Runtime.getRuntime().addShutdownHook(new Thread() { + + @Override + public void run() { + FileUtils.deleteDirectory(dir); + } + }); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/IOUtils.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/IOUtils.java new file mode 100644 index 00000000..0a5cbccc --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/IOUtils.java @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.util; + +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Copied from commons-io-2.2 (org.apache.commons.io.IOUtils) + * Origin license: http://www.apache.org/licenses/LICENSE-2.0 + * @version $Id: IOUtils.java 1304177 2012-03-23 03:36:44Z ggregory $ + */ +public class IOUtils { + + private static final int EOF = -1; + + /** + * The default buffer size ({@value}) to use for + * {@link #copyLarge(InputStream, OutputStream)} + */ + private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; + + /** + * Get the contents of an InputStream as a byte[]. + *

+ * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + * + * @param input the InputStream to read from + * @return the requested byte array + * @throws NullPointerException if the input is null + * @throws IOException if an I/O error occurs + */ + public static byte[] toByteArray(InputStream input) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + copy(input, output); + return output.toByteArray(); + } + + /** + * Copy bytes from an InputStream to an + * OutputStream. + *

+ * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + *

+ * Large streams (over 2GB) will return a bytes copied value of + * -1 after the copy has completed since the correct + * number of bytes cannot be returned as an int. For large streams + * use the copyLarge(InputStream, OutputStream) method. + * + * @param input the InputStream to read from + * @param output the OutputStream to write to + * @return the number of bytes copied, or -1 if > Integer.MAX_VALUE + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static int copy(InputStream input, OutputStream output) throws IOException { + long count = copyLarge(input, output); + if (count > Integer.MAX_VALUE) { + return -1; + } + return (int) count; + } + + /** + * Copy bytes from a large (over 2GB) InputStream to an + * OutputStream. + *

+ * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + *

+ * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. + * + * @param input the InputStream to read from + * @param output the OutputStream to write to + * @return the number of bytes copied + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 1.3 + */ + public static long copyLarge(InputStream input, OutputStream output) throws IOException { + return copyLarge(input, output, new byte[DEFAULT_BUFFER_SIZE]); + } + + /** + * Copy bytes from a large (over 2GB) InputStream to an + * OutputStream. + *

+ * This method uses the provided buffer, so there is no need to use a + * BufferedInputStream. + *

+ * + * @param input the InputStream to read from + * @param output the OutputStream to write to + * @param buffer the buffer to use for the copy + * @return the number of bytes copied + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 2.2 + */ + public static long copyLarge(InputStream input, OutputStream output, byte[] buffer) throws IOException { + long count = 0; + int n = 0; + while (EOF != (n = input.read(buffer))) { + output.write(buffer, 0, n); + count += n; + } + return count; + } + + /** + * close streams + * @param closeable the closeable handler + */ + public static void closeQuietly(Closeable closeable) { + try { + if (closeable != null) { + closeable.close(); + } + } catch (IOException ex) { + // ignore ex + } + } + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/Length.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/Length.java new file mode 100644 index 00000000..f677a69a --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/Length.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.util; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The length rule of the target field. + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Length { + + int value(); +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/MethodUtil.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/MethodUtil.java new file mode 100644 index 00000000..d71e79a9 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/MethodUtil.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.util; + +import java.lang.reflect.Method; + +/** + * According to the input parameter, return the OperationName for the span record, It can determine the unique method + */ + +public class MethodUtil { + + public static String generateOperationName(Method method) { + StringBuilder operationName = new StringBuilder(method.getDeclaringClass() + .getName() + "." + method.getName() + "("); + Class[] parameterTypes = method.getParameterTypes(); + for (int i = 0; i < parameterTypes.length; i++) { + operationName.append(parameterTypes[i].getName()); + if (i < (parameterTypes.length - 1)) { + operationName.append(","); + } + } + operationName.append(")"); + return operationName.toString(); + } + + /** + * This is a low-performance method, recommend to use this when have to, make sure it is only executed once and the + * result is being cached. + */ + public static boolean isMethodExist(ClassLoader classLoader, String className, String methodName, + String... parameterTypes) { + try { + Class clazz = Class.forName(className, true, classLoader); + if (parameterTypes == null || parameterTypes.length == 0) { + clazz.getDeclaredMethod(methodName); + return true; + } else { + Method[] declaredMethods = clazz.getDeclaredMethods(); + for (Method declaredMethod : declaredMethods) { + if (declaredMethod.getName().equals(methodName) + && isParameterTypesEquals(declaredMethod.getParameterTypes(), parameterTypes)) { + return true; + } + } + } + } catch (Exception e) { + // ignore + } + return false; + } + + private static boolean isParameterTypesEquals(Class[] parameterTypeClazz, String[] parameterTypeString) { + if (parameterTypeClazz == null) { + return false; + } + if (parameterTypeClazz.length != parameterTypeString.length) { + return false; + } + for (int i = 0; i < parameterTypeClazz.length; i++) { + if (!parameterTypeClazz[i].getName().equals(parameterTypeString[i])) { + return false; + } + } + return true; + + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/PlaceholderConfigurerSupport.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/PlaceholderConfigurerSupport.java new file mode 100644 index 00000000..3dc200fe --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/PlaceholderConfigurerSupport.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.util; + +public class PlaceholderConfigurerSupport { + + /** + * Default placeholder prefix: {@value} + */ + public static final String DEFAULT_PLACEHOLDER_PREFIX = "${"; + + /** + * Default placeholder suffix: {@value} + */ + public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}"; + + /** + * Default value separator: {@value} + */ + public static final String DEFAULT_VALUE_SEPARATOR = ":"; + +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/PrivateKeyUtil.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/PrivateKeyUtil.java new file mode 100644 index 00000000..52e9a0fe --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/PrivateKeyUtil.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.util; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Base64; + +/** + * Util intends to parse PKCS#1 and PKCS#8 at same time. + */ +public class PrivateKeyUtil { + + private static final String PKCS_1_PEM_HEADER = "-----BEGIN RSA PRIVATE KEY-----"; + private static final String PKCS_1_PEM_FOOTER = "-----END RSA PRIVATE KEY-----"; + private static final String PKCS_8_PEM_HEADER = "-----BEGIN PRIVATE KEY-----"; + private static final String PKCS_8_PEM_FOOTER = "-----END PRIVATE KEY-----"; + + /** + * Load a RSA decryption key from a file (PEM or DER). + */ + public static InputStream loadDecryptionKey(String keyFilePath) throws IOException { + byte[] keyDataBytes = Files.readAllBytes(Paths.get(keyFilePath)); + String keyDataString = new String(keyDataBytes, StandardCharsets.UTF_8); + + if (keyDataString.contains(PKCS_1_PEM_HEADER)) { + // OpenSSL / PKCS#1 Base64 PEM encoded file + keyDataString = keyDataString.replace(PKCS_1_PEM_HEADER, ""); + keyDataString = keyDataString.replace(PKCS_1_PEM_FOOTER, ""); + keyDataString = keyDataString.replace("\n", ""); + return readPkcs1PrivateKey(Base64.getDecoder().decode(keyDataString)); + } + + return new ByteArrayInputStream(keyDataString.getBytes()); + } + + /** + * Create a InputStream instance from raw PKCS#1 bytes. Raw Java API can't recognize ASN.1 format, so we should + * convert it into a pkcs#8 format Java can understand. + */ + private static InputStream readPkcs1PrivateKey(byte[] pkcs1Bytes) { + int pkcs1Length = pkcs1Bytes.length; + int totalLength = pkcs1Length + 22; + byte[] pkcs8Header = new byte[]{ + 0x30, (byte) 0x82, (byte) ((totalLength >> 8) & 0xff), (byte) (totalLength & 0xff), // Sequence + total length + 0x2, 0x1, 0x0, // Integer (0) + 0x30, 0xD, 0x6, 0x9, 0x2A, (byte) 0x86, 0x48, (byte) 0x86, (byte) 0xF7, 0xD, 0x1, 0x1, 0x1, 0x5, 0x0, // Sequence: 1.2.840.113549.1.1.1, NULL + 0x4, (byte) 0x82, (byte) ((pkcs1Length >> 8) & 0xff), (byte) (pkcs1Length & 0xff) // Octet string + length + }; + StringBuilder pkcs8 = new StringBuilder(PKCS_8_PEM_HEADER); + pkcs8.append("\n").append(new String(Base64.getEncoder().encode(join(pkcs8Header, pkcs1Bytes)))); + pkcs8.append("\n").append(PKCS_8_PEM_FOOTER); + return new ByteArrayInputStream(pkcs8.toString().getBytes()); + } + + private static byte[] join(byte[] byteArray1, byte[] byteArray2) { + byte[] bytes = new byte[byteArray1.length + byteArray2.length]; + System.arraycopy(byteArray1, 0, bytes, 0, byteArray1.length); + System.arraycopy(byteArray2, 0, bytes, byteArray1.length, byteArray2.length); + return bytes; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/PropertyPlaceholderHelper.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/PropertyPlaceholderHelper.java new file mode 100644 index 00000000..15248be4 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/PropertyPlaceholderHelper.java @@ -0,0 +1,208 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.util; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +/** + * Utility class for working with Strings that have placeholder values in them. A placeholder takes the form {@code + * ${name}}. Using {@code PropertyPlaceholderHelper} these placeholders can be substituted for user-supplied values.

+ * Values for substitution can be supplied using a {@link Properties} instance or using a {@link PlaceholderResolver}. + */ +public enum PropertyPlaceholderHelper { + + INSTANCE( + PlaceholderConfigurerSupport.DEFAULT_PLACEHOLDER_PREFIX, + PlaceholderConfigurerSupport.DEFAULT_PLACEHOLDER_SUFFIX, PlaceholderConfigurerSupport.DEFAULT_VALUE_SEPARATOR, + true); + + private final String placeholderPrefix; + + private final String placeholderSuffix; + + private final String simplePrefix; + + private final String valueSeparator; + + private final boolean ignoreUnresolvablePlaceholders; + + /** + * Creates a new {@code PropertyPlaceholderHelper} that uses the supplied prefix and suffix. + * + * @param placeholderPrefix the prefix that denotes the start of a placeholder + * @param placeholderSuffix the suffix that denotes the end of a placeholder + * @param valueSeparator the separating character between the placeholder variable and the + * associated default value, if any + * @param ignoreUnresolvablePlaceholders indicates whether unresolvable placeholders should be ignored ({@code + * true}) or cause an exception ({@code false}) + */ + PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix, String valueSeparator, + boolean ignoreUnresolvablePlaceholders) { + if (StringUtil.isEmpty(placeholderPrefix) || StringUtil.isEmpty(placeholderSuffix)) { + throw new UnsupportedOperationException("'placeholderPrefix or placeholderSuffix' must not be null"); + } + + final Map wellKnownSimplePrefixes = new HashMap(4); + + wellKnownSimplePrefixes.put("}", "{"); + wellKnownSimplePrefixes.put("]", "["); + wellKnownSimplePrefixes.put(")", "("); + + this.placeholderPrefix = placeholderPrefix; + this.placeholderSuffix = placeholderSuffix; + String simplePrefixForSuffix = wellKnownSimplePrefixes.get(this.placeholderSuffix); + if (simplePrefixForSuffix != null && this.placeholderPrefix.endsWith(simplePrefixForSuffix)) { + this.simplePrefix = simplePrefixForSuffix; + } else { + this.simplePrefix = this.placeholderPrefix; + } + this.valueSeparator = valueSeparator; + this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders; + } + + /** + * Replaces all placeholders of format {@code ${name}} with the corresponding property from the supplied {@link + * Properties}. + * + * @param value the value containing the placeholders to be replaced + * @param properties the {@code Properties} to use for replacement + * @return the supplied value with placeholders replaced inline + */ + public String replacePlaceholders(String value, final Properties properties) { + return replacePlaceholders(value, new PlaceholderResolver() { + + @Override + public String resolvePlaceholder(String placeholderName) { + return getConfigValue(placeholderName, properties); + } + }); + } + + private String getConfigValue(String key, final Properties properties) { + String value = System.getProperty(key); + if (value == null) { + value = System.getenv(key); + } + if (value == null) { + value = properties.getProperty(key); + } + return value; + } + + /** + * Replaces all placeholders of format {@code ${name}} with the value returned from the supplied {@link + * PlaceholderResolver}. + * + * @param value the value containing the placeholders to be replaced + * @param placeholderResolver the {@code PlaceholderResolver} to use for replacement + * @return the supplied value with placeholders replaced inline + */ + public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) { + return parseStringValue(value, placeholderResolver, new HashSet()); + } + + protected String parseStringValue(String value, PlaceholderResolver placeholderResolver, + Set visitedPlaceholders) { + + StringBuilder result = new StringBuilder(value); + + int startIndex = value.indexOf(this.placeholderPrefix); + while (startIndex != -1) { + int endIndex = findPlaceholderEndIndex(result, startIndex); + if (endIndex != -1) { + String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex); + String originalPlaceholder = placeholder; + if (!visitedPlaceholders.add(originalPlaceholder)) { + throw new IllegalArgumentException( + "Circular placeholder reference '" + originalPlaceholder + "' in property definitions"); + } + // Recursive invocation, parsing placeholders contained in the placeholder key. + placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders); + // Now obtain the value for the fully resolved key... + String propVal = placeholderResolver.resolvePlaceholder(placeholder); + if (propVal == null && this.valueSeparator != null) { + int separatorIndex = placeholder.indexOf(this.valueSeparator); + if (separatorIndex != -1) { + String actualPlaceholder = placeholder.substring(0, separatorIndex); + String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length()); + propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder); + if (propVal == null) { + propVal = defaultValue; + } + } + } + if (propVal != null) { + // Recursive invocation, parsing placeholders contained in the + // previously resolved placeholder value. + propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders); + result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal); + startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length()); + } else if (this.ignoreUnresolvablePlaceholders) { + // Proceed with unprocessed value. + startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length()); + } else { + throw new IllegalArgumentException( + "Could not resolve placeholder '" + placeholder + "'" + " in value \"" + value + "\""); + } + visitedPlaceholders.remove(originalPlaceholder); + } else { + startIndex = -1; + } + } + return result.toString(); + } + + private int findPlaceholderEndIndex(CharSequence buf, int startIndex) { + int index = startIndex + this.placeholderPrefix.length(); + int withinNestedPlaceholder = 0; + while (index < buf.length()) { + if (StringUtil.substringMatch(buf, index, this.placeholderSuffix)) { + if (withinNestedPlaceholder > 0) { + withinNestedPlaceholder--; + index = index + this.placeholderSuffix.length(); + } else { + return index; + } + } else if (StringUtil.substringMatch(buf, index, this.simplePrefix)) { + withinNestedPlaceholder++; + index = index + this.simplePrefix.length(); + } else { + index++; + } + } + return -1; + } + + /** + * Strategy interface used to resolve replacement values for placeholders contained in Strings. + */ + public interface PlaceholderResolver { + + /** + * Resolve the supplied placeholder name to the replacement value. + * + * @param placeholderName the name of the placeholder to resolve + * @return the replacement value, or {@code null} if no replacement is to be made + */ + String resolvePlaceholder(String placeholderName); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/ReflectUtil.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/ReflectUtil.java new file mode 100644 index 00000000..091e5b27 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/ReflectUtil.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.util; + +import com.example.agent.core.logging.api.ILog; +import com.example.agent.core.logging.api.LogManager; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + +public class ReflectUtil { + + private static final ILog LOGGER = LogManager.getLogger(ReflectUtil.class); + + public static List getStaticFieldsFromType(Class clazz, Class declaredType) { + Field[] fields = clazz.getDeclaredFields(); + List result = new ArrayList<>(); + for (Field field : fields) { + if (field.getType().isAssignableFrom(declaredType) + && Modifier.isStatic(field.getModifiers())) { + field.setAccessible(true); + result.add(field); + } + } + return result; + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/RegexUtil.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/RegexUtil.java new file mode 100644 index 00000000..3b1162db --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/RegexUtil.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.util; + +import java.util.regex.Pattern; + +public class RegexUtil { + + private static final String TOMCAT_NAME_PATTERN_STRING = "http\\S+nio\\S+-exec-"; + private static final Pattern TOMCAT_NAME_PATTERN = Pattern.compile(TOMCAT_NAME_PATTERN_STRING); + + public static boolean isTomcatNameMatch(String executorName) { + return TOMCAT_NAME_PATTERN.matcher(executorName).find(); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/RunnableWithExceptionProtection.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/RunnableWithExceptionProtection.java new file mode 100644 index 00000000..f4ca6b9d --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/RunnableWithExceptionProtection.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.util; + +public class RunnableWithExceptionProtection implements Runnable { + + private Runnable run; + private CallbackWhenException callback; + + public RunnableWithExceptionProtection(Runnable run, CallbackWhenException callback) { + this.run = run; + this.callback = callback; + } + + @Override + public void run() { + try { + run.run(); + } catch (Throwable t) { + callback.handle(t); + } + } + + public interface CallbackWhenException { + + void handle(Throwable t); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/StringUtil.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/StringUtil.java new file mode 100644 index 00000000..250c1d25 --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/StringUtil.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.util; + +import java.util.function.Consumer; + +public final class StringUtil { + + public static boolean isEmpty(String str) { + return str == null || str.length() == 0; + } + + public static boolean isNotEmpty(String str) { + return !isEmpty(str); + } + + public static boolean isBlank(String str) { + return str == null || isEmpty(str.trim()); + } + + public static boolean isNotBlank(String str) { + return !isBlank(str); + } + + public static void setIfPresent(String value, Consumer setter) { + if (isNotEmpty(value)) { + setter.accept(value); + } + } + + public static String join(final char delimiter, final String... strings) { + if (strings.length == 0) { + return null; + } + if (strings.length == 1) { + return strings[0]; + } + int length = strings.length - 1; + for (final String s : strings) { + if (s == null) { + continue; + } + length += s.length(); + } + final StringBuilder sb = new StringBuilder(length); + if (strings[0] != null) { + sb.append(strings[0]); + } + for (int i = 1; i < strings.length; ++i) { + if (!isEmpty(strings[i])) { + sb.append(delimiter).append(strings[i]); + } else { + sb.append(delimiter); + } + } + return sb.toString(); + } + + public static boolean substringMatch(CharSequence str, int index, CharSequence substring) { + if (index + substring.length() > str.length()) { + return false; + } + for (int i = 0; i < substring.length(); i++) { + if (str.charAt(index + i) != substring.charAt(i)) { + return false; + } + } + return true; + } + + public static String cut(String str, int threshold) { + if (isEmpty(str) || str.length() <= threshold) { + return str; + } + return str.substring(0, threshold); + } + + public static String trim(final String str, final char ch) { + if (isEmpty(str)) { + return null; + } + + final char[] chars = str.toCharArray(); + + int i = 0, j = chars.length - 1; + // noinspection StatementWithEmptyBody + for (; i < chars.length && chars[i] == ch; i++) { + } + // noinspection StatementWithEmptyBody + for (; j > 0 && chars[j] == ch; j--) { + } + + return new String(chars, i, j - i + 1); + } +} diff --git a/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/ThreadPoolPropertyKey.java b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/ThreadPoolPropertyKey.java new file mode 100644 index 00000000..c39a044c --- /dev/null +++ b/cook-async-agent/cook-async-agent-core/src/main/java/com/example/agent/core/util/ThreadPoolPropertyKey.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.agent.core.util; + +public interface ThreadPoolPropertyKey { + + String THREAD_POOL_ID = "threadPoolId"; + + String CORE_POOL_SIZE = "corePoolSize"; + + String MAXIMUM_POOL_SIZE = "maximumPoolSize"; + + String ALLOW_CORE_THREAD_TIME_OUT = "allowCoreThreadTimeOut"; + + String KEEP_ALIVE_TIME = "keepAliveTime"; + + String BLOCKING_QUEUE = "blockingQueue"; + + String QUEUE_CAPACITY = "queueCapacity"; + + String REJECTED_HANDLER = "rejectedHandler"; + + String EXECUTE_TIME_OUT = "executeTimeOut"; +} diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/pom.xml b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/pom.xml index 995edfeb..8956f0a8 100644 --- a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/pom.xml +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/pom.xml @@ -12,6 +12,11 @@ cook-async-agent-threadpool-plugin + + com.example + threadlocal-tool + ${revision} + javax.servlet javax.servlet-api @@ -25,5 +30,10 @@ 5.2.15.RELEASE provided + + org.slf4j + slf4j-api + provided + \ No newline at end of file diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/AbstractThreadingPoolInterceptor.java b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/AbstractThreadingPoolInterceptor.java new file mode 100644 index 00000000..993a382a --- /dev/null +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/AbstractThreadingPoolInterceptor.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.example.agent.plugin.thread; + + +import com.example.ParameterHolder; +import com.example.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import com.example.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; +import com.example.agent.core.plugin.interceptor.enhance.MethodInterceptResult; +import org.slf4j.MDC; + +import java.lang.reflect.Method; +import java.util.Map; + +public abstract class AbstractThreadingPoolInterceptor implements InstanceMethodsAroundInterceptor { + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, MethodInterceptResult result) throws Throwable { + + + if (allArguments == null || allArguments.length < 1) { + return; + } + + Object argument = allArguments[0]; + + Object wrappedObject = wrap(argument); + if (wrappedObject != null) { + allArguments[0] = wrappedObject; + } + } + public abstract Object wrap(Object param); + + @Override + public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, Object ret) throws Throwable { + return ret; + } + + @Override + public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, Throwable t) { + + } + + protected static Map getContextForTask() { + return MDC.getCopyOfContextMap(); + } + + protected static Map getContextForHold() { + return ParameterHolder.getParameterMap(); + } +} diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolExecuteMethodInterceptor.java b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolExecuteMethodInterceptor.java new file mode 100644 index 00000000..cfa16c21 --- /dev/null +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolExecuteMethodInterceptor.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.example.agent.plugin.thread; + + +import com.example.agent.plugin.thread.wrapper.RunnableWrapper; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; + +import java.util.Map; +import java.util.concurrent.RunnableFuture; + +public class ThreadPoolExecuteMethodInterceptor extends AbstractThreadingPoolInterceptor { + + + @Override + public Object wrap(final Object param) { + if (param instanceof RunnableWrapper) { + return null; + } + + if (param instanceof RunnableFuture) { + return null; + } + + if (param instanceof Runnable) { + Runnable runnable = (Runnable) param; + Map contextForTask = getContextForTask(); + Map contextForHold = getContextForHold(); + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + return new RunnableWrapper(runnable,contextForTask,contextForHold,requestAttributes); + } + return param; + } + + +} diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolSubmitMethodInterceptor.java b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolSubmitMethodInterceptor.java new file mode 100644 index 00000000..c7e5ecbe --- /dev/null +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolSubmitMethodInterceptor.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.example.agent.plugin.thread; + + +import com.example.agent.plugin.thread.wrapper.CallableWrapper; +import com.example.agent.plugin.thread.wrapper.RunnableWrapper; + +import java.util.Map; +import java.util.concurrent.Callable; + +public class ThreadPoolSubmitMethodInterceptor extends AbstractThreadingPoolInterceptor { + + @Override + public Object wrap(final Object param) { + if (param instanceof RunnableWrapper || param instanceof CallableWrapper) { + return null; + } + if (param instanceof Callable) { + Callable callable = (Callable) param; + Map contextForTask = getContextForTask(); + Map contextForHold = getContextForHold(); + return new CallableWrapper(callable,contextForTask,contextForHold); + } + if (param instanceof Runnable) { + Runnable runnable = (Runnable) param; + Map contextForTask = getContextForTask(); + Map contextForHold = getContextForHold(); + return new RunnableWrapper(runnable,contextForTask,contextForHold); + } + return null; + } +} diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/define/ThreadPoolExecutorInstrumentation.java b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/define/ThreadPoolExecutorInstrumentation.java new file mode 100644 index 00000000..c372f6d6 --- /dev/null +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/define/ThreadPoolExecutorInstrumentation.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.example.agent.plugin.thread.define; + +import com.example.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import com.example.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import com.example.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; +import com.example.agent.core.plugin.match.ClassMatch; +import com.example.agent.core.plugin.match.HierarchyMatch; +import com.example.agent.core.plugin.match.MultiClassNameMatch; +import com.example.agent.core.plugin.match.logical.LogicalMatchOperation; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.ElementMatchers; + + +public class ThreadPoolExecutorInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + + private static final String ENHANCE_CLASS = "java.util.concurrent.ThreadPoolExecutor"; + + private static final String INTERCEPT_EXECUTE_METHOD = "execute"; + + private static final String INTERCEPT_SUBMIT_METHOD = "submit"; + + private static final String INTERCEPT_EXECUTE_METHOD_HANDLE = "com.example.agent.plugin.thread.ThreadPoolExecuteMethodInterceptor"; + + private static final String INTERCEPT_SUBMIT_METHOD_HANDLE = "com.example.agent.plugin.thread.ThreadPoolSubmitMethodInterceptor"; + + @Override + public boolean isBootstrapInstrumentation() { + return true; + } + + @Override + protected ClassMatch enhanceClass() { + return LogicalMatchOperation.or(HierarchyMatch.byHierarchyMatch(ENHANCE_CLASS), MultiClassNameMatch.byMultiClassMatch(ENHANCE_CLASS)); + } + + @Override + public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[0]; + } + + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[]{ + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return ElementMatchers.named(INTERCEPT_EXECUTE_METHOD); + } + + @Override + public String getMethodsInterceptor() { + return INTERCEPT_EXECUTE_METHOD_HANDLE; + } + + @Override + public boolean isOverrideArgs() { + return true; + } + }, + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return ElementMatchers.named(INTERCEPT_SUBMIT_METHOD); + } + + @Override + public String getMethodsInterceptor() { + return INTERCEPT_SUBMIT_METHOD_HANDLE; + } + + @Override + public boolean isOverrideArgs() { + return true; + } + } + }; + } +} diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/BaseWrapper.java b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/BaseWrapper.java new file mode 100644 index 00000000..bb29234c --- /dev/null +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/BaseWrapper.java @@ -0,0 +1,48 @@ +package com.example.agent.plugin.thread.wrapper; + +import com.example.ParameterHolder; +import org.slf4j.MDC; + +import java.util.HashMap; +import java.util.Map; + +/** + * @program: cook-frame + * @description: + * @author: k + * @create: 2023-07-21 + **/ +public class BaseWrapper { + + protected static Map> preprocess(final Map parentMdcContext, final Map parentHoldContext){ + Map> map = new HashMap<>(); + Map holdContext = ParameterHolder.getParameterMap(); + Map mdcContext = MDC.getCopyOfContextMap(); + if (parentMdcContext == null) { + MDC.clear(); + } else { + MDC.setContextMap(parentMdcContext); + } + if (parentHoldContext == null) { + ParameterHolder.removeParameterMap(); + } else { + ParameterHolder.setParameterMap(parentHoldContext); + } + map.put("holdContext",holdContext); + map.put("mdcContext",mdcContext); + return map; + } + + protected static void postProcess(Map mdcContext, Map holdContext){ + if (mdcContext == null) { + MDC.clear(); + } else { + MDC.setContextMap(mdcContext); + } + if (holdContext == null) { + ParameterHolder.removeParameterMap(); + } else { + ParameterHolder.setParameterMap(holdContext); + } + } +} diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/CallableWrapper.java b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/CallableWrapper.java new file mode 100644 index 00000000..23945916 --- /dev/null +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/CallableWrapper.java @@ -0,0 +1,42 @@ +package com.example.agent.plugin.thread.wrapper; + +import lombok.AllArgsConstructor; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; + +import java.util.Map; +import java.util.concurrent.Callable; + +/** + * @program: cook-frame + * @description: + * @author: k + * @create: 2023-07-21 + **/ +@AllArgsConstructor +public class CallableWrapper extends BaseWrapper implements Callable { + + private final Callable callable; + + private final Map parentMdcContext; + + private final Map parentHoldContext; + + private final RequestAttributes requestAttributes; + + @Override + public Object call() throws Exception { + Map> preprocess = preprocess(parentMdcContext, parentHoldContext); + Map holdContext = preprocess.get("holdContext"); + Map mdcContext = preprocess.get("mdcContext"); + if (requestAttributes != null) { + RequestContextHolder.setRequestAttributes(requestAttributes); + } + try { + return callable.call(); + }finally { + postProcess(mdcContext,holdContext); + RequestContextHolder.resetRequestAttributes(); + } + } +} diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/RunnableWrapper.java b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/RunnableWrapper.java new file mode 100644 index 00000000..b3b41194 --- /dev/null +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/RunnableWrapper.java @@ -0,0 +1,41 @@ +package com.example.agent.plugin.thread.wrapper; + +import lombok.AllArgsConstructor; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; + +import java.util.Map; + +/** + * @program: cook-frame + * @description: + * @author: 星哥 + * @create: 2023-07-21 + **/ +@AllArgsConstructor +public class RunnableWrapper extends BaseWrapper implements Runnable{ + + private final Runnable runnable; + + private final Map parentMdcContext; + + private final Map parentHoldContext; + + private final RequestAttributes requestAttributes; + + @Override + public void run() { + Map> preprocess = preprocess(parentMdcContext, parentHoldContext); + Map holdContext = preprocess.get("holdContext"); + Map mdcContext = preprocess.get("mdcContext"); + if (requestAttributes != null) { + RequestContextHolder.setRequestAttributes(requestAttributes); + } + try { + runnable.run(); + } finally { + postProcess(mdcContext,holdContext); + RequestContextHolder.resetRequestAttributes(); + } + } +} diff --git a/cook-async-agent/cook-async-agent-plugin/pom.xml b/cook-async-agent/cook-async-agent-plugin/pom.xml index 760356df..140feffb 100644 --- a/cook-async-agent/cook-async-agent-plugin/pom.xml +++ b/cook-async-agent/cook-async-agent-plugin/pom.xml @@ -36,7 +36,7 @@ net.bytebuddy ${shade.package}.${shade.net.bytebuddy.source} - ${project.build.directory}${sdk.plugin.related.dir}/../../../agent + ${project.build.directory}${sdk.plugin.related.dir}/../../../cookasyncagent ${agent.package.dest.dir}/plugins diff --git a/pom.xml b/pom.xml index 75858067..212935da 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,7 @@ server-client course-case cook-async-agent + threadlocal-tool diff --git a/threadlocal-tool/.gitignore b/threadlocal-tool/.gitignore new file mode 100644 index 00000000..a2a3040a --- /dev/null +++ b/threadlocal-tool/.gitignore @@ -0,0 +1,31 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/** +!**/src/test/** + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ diff --git a/threadlocal-tool/mvnw b/threadlocal-tool/mvnw new file mode 100644 index 00000000..a16b5431 --- /dev/null +++ b/threadlocal-tool/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/threadlocal-tool/mvnw.cmd b/threadlocal-tool/mvnw.cmd new file mode 100644 index 00000000..c8d43372 --- /dev/null +++ b/threadlocal-tool/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/threadlocal-tool/pom.xml b/threadlocal-tool/pom.xml new file mode 100644 index 00000000..55c8056e --- /dev/null +++ b/threadlocal-tool/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + + com.example + cook-frame + ${revision} + + + + threadlocal-tool + threadlocal-tool + 公共 + + + 1.8 + UTF-8 + UTF-8 + + + + + commons-codec + commons-codec + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 8 + 8 + UTF-8 + + + + + + diff --git a/threadlocal-tool/src/main/java/com/example/ParameterHolder.java b/threadlocal-tool/src/main/java/com/example/ParameterHolder.java new file mode 100644 index 00000000..2b70b936 --- /dev/null +++ b/threadlocal-tool/src/main/java/com/example/ParameterHolder.java @@ -0,0 +1,57 @@ +package com.example; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +/** + * @program: cook-frame + * @description: ThreadLocal操作持有器 + * @author: 星哥 + * @create: 2023-07-09 + **/ +public class ParameterHolder { + + private static final ThreadLocal> threadLocalMap = new ThreadLocal<>(); + + + public static void setParameter(String name, String value) { + Map map = threadLocalMap.get(); + if (map == null) { + map = new HashMap<>(); + } + map.put(name, value); + threadLocalMap.set(map); + } + + public static String getParameter(String name) { + return Optional.ofNullable(threadLocalMap.get()).map(map -> map.get(name)).orElse(null); + } + + public static void removeParameter(String name) { + Map map = threadLocalMap.get(); + if (map != null) { + map.remove(name); + } + } + + public static ThreadLocal> getThreadLocal() { + return threadLocalMap; + } + + public static Map getParameterMap() { + Map map = threadLocalMap.get(); + if (map == null) { + map = new HashMap<>(); + } + return map; + } + + public static void setParameterMap(Map map) { + threadLocalMap.set(map); + } + + public static void removeParameterMap(){ + threadLocalMap.remove(); + } +} -- Gitee From b790e9e873c34fb881eda9cc1f86588f636e0784 Mon Sep 17 00:00:00 2001 From: shining-stars-lk <1031900093@qq.com> Date: Fri, 21 Jul 2023 19:35:28 +0800 Subject: [PATCH 03/11] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AD=97=E8=8A=82?= =?UTF-8?q?=E7=A0=81=E5=A2=9E=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/thread/ThreadPoolSubmitMethodInterceptor.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolSubmitMethodInterceptor.java b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolSubmitMethodInterceptor.java index c7e5ecbe..b4e980b2 100644 --- a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolSubmitMethodInterceptor.java +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolSubmitMethodInterceptor.java @@ -21,6 +21,8 @@ package com.example.agent.plugin.thread; import com.example.agent.plugin.thread.wrapper.CallableWrapper; import com.example.agent.plugin.thread.wrapper.RunnableWrapper; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; import java.util.Map; import java.util.concurrent.Callable; @@ -36,13 +38,15 @@ public class ThreadPoolSubmitMethodInterceptor extends AbstractThreadingPoolInte Callable callable = (Callable) param; Map contextForTask = getContextForTask(); Map contextForHold = getContextForHold(); - return new CallableWrapper(callable,contextForTask,contextForHold); + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + return new CallableWrapper(callable,contextForTask,contextForHold,requestAttributes); } if (param instanceof Runnable) { Runnable runnable = (Runnable) param; Map contextForTask = getContextForTask(); Map contextForHold = getContextForHold(); - return new RunnableWrapper(runnable,contextForTask,contextForHold); + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + return new RunnableWrapper(runnable,contextForTask,contextForHold,requestAttributes); } return null; } -- Gitee From 04e43f192a7b1c63a0a6849a69ebc3272e49e723 Mon Sep 17 00:00:00 2001 From: shining-stars-lk <1031900093@qq.com> Date: Sat, 22 Jul 2023 15:41:25 +0800 Subject: [PATCH 04/11] =?UTF-8?q?=E8=B0=83=E6=95=B4=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...nc-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar | Bin 8285 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 cook-async-agent/hippo4j-agent/plugins/cook-async-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar diff --git a/cook-async-agent/hippo4j-agent/plugins/cook-async-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar b/cook-async-agent/hippo4j-agent/plugins/cook-async-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar deleted file mode 100644 index 53465dbaf869b2545903b76f6304513d2d58fd9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8285 zcmb_h1z1$w)~2LOy1QWrNhKtt8M?chpy@DPg2bnvn)2q#Gop1p!3_6cEXO zM*Tk2dq1xJ_pX^U&v~BN>wVAOXRp22ewVs3G71p_IyyRn$L&2`gdYq80R;glt1Sgk zRF&g7?L|O9Mo?EqLx;CO`rb_aADxL{E&g@}N~tQ!$!ckH1LZye`}A`mh9DhU&dT`tD~OH$q{JK09+ zTXGq%+;#sv>u{BdVg4v#A^w#&uiqejeYU&=XP_aB*#dU`^RuDA{@(yA6nhj)mav7W99AT>Y)ho^z!g_fsL_+mxC*aiI3aL*}~JaRL4k-Py_!| z)o7|lmz{XKER)!X+eAHpqqSR>i(MLNN$PP;qm@CG_{@6<^S0SBhQxaK$iX7swmi9A zEtcT8y}(TFSgNOO%clXr$?5WjFoH6eqr#?vIzu%^b&`J0K0(`m6600P_{%K$$ULLn ziKN^u`H8ZPYm}_ksJ(j>qk5*pOXxDwWn4Ut_((4pm#2oQWoq^^CN8Hc$rze@ZWE8~ zt-ohC;`pfY?n*ID8^vg@i{|aJH^PHuJ|_F4yiB|&dfZPR+oN9#IK?sHknyTn zra@7Q152V)bBGu>-zptM)+C-pag4<*Id^xWC|lRupuoRNeU;wtFj9v8WD{aAkC{8& zw^H@o5Gjg64yDSj0;&Do@O~ebnEJD&qhOtK{&!UXm!}LBCW^Q<{_2t#dY%dv(sU*m zn|#JYjNz0>sl1oV{4KX0l3tC|pn=r&xg+|qbG&5o?^~ykRnsE*j50y^d{Krte+t;ymMGm=ogvPlHIP#qS{=sV*K3{OpS z9Gm4{a{I8E)|ypR7h)P$o@7{k6r0IjGo885vMe~%p5_!MS@bq7($gGVGvZ-?od}5$ z2no@XDv&h|h@YvR8C4JMI&8E)Y&>?QBl(hV=i6TVE`v>@IeE+fEW4%6yKk!=aqX-v z_R92w{N+RA5lFRU7Cp0{Q|!{widB3vGqR~dlqKIR&FNY9wlDT_z_p=Qm^X6|gs<}- zVNBXeEU(JfXcktcug@)#fRN)z7|_>C_!;`_xV9F#k0SK3oFfX_^LltvPTgX))-yUq zPS$l|(E~}Q{ckDt+e^qPCfjmL=c3UG84Ox-<7Pz5Xr+E8Wza&71Ipc`nzIKJJY?=_ zQ7(D-I{wyUPBu#~k|x;Vn&MSG#{{Q`A`#a3)8Uj z&8SpI0RaJ0A+u~0b4nr4%v_~OmFUd-L4pIGQxw|WR{MZ$w1b=&J05kJdvevlYZ?5W zgTf162Cu&TOl$TGQNPtH(q*o)US#5Z3v=BBvF1+88((0L&Jb~0E6&bDV%XO03COa( zQJ3`Rhs#2F1;z{c=)lz25-z(|GNs$E;yM99pD&;_^>vPDf%dT_J+Cg}0<~043_a37 z={JZaEZ&uj+CzLzt8ZUIWK0cWc>7NuDvQ&#ZgUmQR(13Bdqu#a=6;q=X)}m9(J3bi zi5q{F7eaq1O(Fd*f4h$8uCHq1`az_7n+x!*_|iv!GRm$mLv_`rvUu+bL%SSOltB#N zimC;s3{gk_kNj}Z)i1D#DZod%9b6|=a#vS-bVHL z?}Z2~f+il0zx%AtzR3N7Uj;YU5!W`tB5Z}?b!&y{jdy%;{tCG?FNNuv^tZR~u}p?aPY1xhiS7u&n^aXPyfm(1j&> zY6r^36SqcBO|HB&IT6N}0XI19BWu)Cv-IW!2&0kS6O1n%_6g`cyF+eU#q8a;qcGf^ znl+WESx1?)>etpTa8C(!+|E2tlUH@llx>QT%FZI4ox z>V~#gIAtBitww~<&@l+U!(84T2`IrV(t7r#TQU8%=Tv1lH@U0rEdFvgvL}s-XPAF$rJj!Eb zHj4m(v#)`(dtJSv5f(Up7Y2^%|8TSUD{NdmXKvsJ4f-&2i9m69060*TSK|)RH>9%? zlM?kcoJeQ(v_Yt2c&XI^Q-y} zl&g5=1iaF<^%$cQdlBwj-rUa0$2G2?OX0#_!OtoFG~n-awP9 znoKfnj1LJDYdl-gA{ z-^|o3*T(Qh>`BW<6cIH!h7c#&7Bx0Up&OTNBC+;#yTI9$n}aPo8Clmi$&P?IS~r{e zGSU6iiQFTXj(4tpa(HU6MMZ6doju=;8?A3qcgz6|%x<3HB`emxELa-F!I{lMtdVfn z8l3NIbR87RFmF+}izy)=>SK#%-HT#Mu!dygJLI$J_K4nWdWv(IL06e=F)&hE1d80S z)Y(*)0{W0mtu4;O#80cXsf4t^pE!1!yg5{%GY!TF?eVqika0?B0t_6)wK)&I*6=;5 z;VDtS#$MOv=F>1qR6-bT@Z7OxyWSNCPZNrnwTG)}=#Z}su{rXqIaaM`HtO`AWwSsQ zCI=0@o{vc%P7-w7iBnK4#$NMB>oOWO?kwPgMh@h@P>t|u3UzUpcVc>i;wP5hk+Afc zTxReSxpVKy9^pywi!W4WiS~CF@@wtsq~{VcY&GOj<>wam?N?EE9y+IYI(dkwnP=R} zE*o1z$O#FVh}s=r9NGpo(QKXF%6WjdhLX1^Aya+jS!!H=ZU#Y;IzUS5Vaw$z|5=>R zb%Yoc+6|MWI|Xey`!mZe12<#WJHnP!!rP$P8fphcdDi}ycLL43lotC9 zqc8LR#M!sHbCX82qJ==+GbagrrCG!0}qqG5rUis9i#X%tt5Zf7O$C-hW7b{8$3{xkH`GqEZs6PK{DDb9j-!kV;k(wrKgIVmAGl z)p1$7w6)n36B`4giVYPaFldmdzqcxWQ5PRQbe`D%Q8B9Er*{MWn06~OwWD*B13erijJe)C#r|pw zyYcw&KoiS`D9TY=1?hec_fSc?Bu<6%<6r{foO?R5_1@9 zjHef|I$;#()6Q+1@}_imve*LIpVHzw`BYpM6e3(y0hm3QKuV4KY+*!eUv9`;czxre zUFmJ3nam}D+L1HCIdfiYmxK5hti(Y!-Q)`mB9PW#jzN^Q*d4sgCaEl(!PjK&r0(;f zpROKzU*nV!@sYtpNpJVnFiOL2j+h$>{p==5fi8j?{~^*&QVA_COk@hPpb^su-;-IqHJ`DpZ@j?q1YkN_uHhFHGr3lsa zrXn%Eb#pvCzKEGOAgvU%GFtnBh0bz+4lnt}0e)u)mZRRXh5l5viD)5jZjDlxf$?)o zRL^eS{!1n^c7-p`9tEY+JKYf)c~?Ld55bxQm_`9dLy;2@p=uLEk{1M*tet0fPT*x z`6Ot6F&5W8KTG=E*?1C?EZOc%w(_0RSFc8cV@miS%XsRhnGv#OqIvhzCz7zn+$`7vDJzR9D{N{ZjsN8(pPSq z%nB^jxh=-@EUIw@Xac!e7aS`l$`>WSTSMvhb^#s)JqJ=)4`9h^(S-bpm`7 zf4E`dij9_;>my$L;PUY;HzhMecK3X7&^u%oLYz_tt;{Ef>(3Dj!ZxREnHGZV&?fAc zFHO&$oX)u;4{2w6=!Z@&8r|yXjyJ0>J7EK~>Eac~L!e8j*GjR#f*-gY zzhMJKYG~m?ep@e!aI0W%KER;7%bn;72gxg;jp^mX)SQ8j19x@QfIP)AYa*p)$OeN4 zZb%OLI_!8QPZO+C%&D}E5p?+sRgDFe-NsOlMf2|u+um_LsS2@5z$8(`b!Z8>&7}6p z2Eh*)?b?`(WSVdy(R0@;p&f*GzwtdgVAQ0u0Kha&8K72Oz)ZLHLJTY*Bx0UQ^twX{ zrNl487Q@1zZJL~`C_lcm$o2t_bWU)Nj)eyHD~K`K6RS|2khg`bw7$J3ThVvQ$^)D< zbUAapYp=`=KWJF1#}rf24G$wvBwfRMZOqA0qL{_@`YoC;C{{o6I-?HNDE?`b!WT67 z+yNg>rkx=oAOye`(SO!G;dAG2P1eQ2$L7zpL&|@3hpDLC{~twE;$kQ(SJ(u%@bm*& z0lsRbfN#pA8%*T;KJPCSDWRc13)!;&HJcl(pI{f~QY{nZc3z@D(tTQ`ou@rQ#Mait zv@Gb9cg+s`fn_F8pmh9G;+hBSJH0|ouG>rM~iWcTq}AhKoe&{mG#D66K$(~K zG3r=f5Ozz~b*wy5;gAzekM$7G_4+(*$-WR|Mg}-)S?`>pIN;7OGeog~4qhK>!lfV1 zB(Pv-YAAb*b2=_{vl$#h;P`qt>FVK7L#0b4tHSec9{-Vzu9+0MnT)9ls!7zbisn2b zHZqr?j4Sr#vDaUc*4z=XYS*f-RX5MuTy`yXW>$>wmF)@ET0$gG7(uL08L;b0u0G@N z#&Rs66e^$;Y1$=WIDqYL#g8FJjN!pa=#e~PO8shpd>GkGEAVUpH zwO70Aoian4smo3RMdoM>Bif?V1J}Svhl@;iplzDVSSBZ;&j5o)J|xI*95)W4n|N6{ z9WeNu_AbGDEK6{`9SrMF0PIp%Mnob)__=KJS4{?9w)xrqj(KS`63ay}bmthbyYY))z86?7LW37n&W#B+u0IaPw@!V3sPAas%PYTv{v;Zo zBf{=({yylhXWxG;uKddWlk)Zxd-z3|lZE9s9}2Ryepw}*sq z(x0-_U!CEN|5`PEb{--AVcq$brd;F Date: Sat, 22 Jul 2023 15:42:04 +0800 Subject: [PATCH 05/11] =?UTF-8?q?=E8=B0=83=E6=95=B4=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar | Bin 414165 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 cook-async-agent/agent/plugins/cook-async-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar diff --git a/cook-async-agent/agent/plugins/cook-async-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar b/cook-async-agent/agent/plugins/cook-async-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar deleted file mode 100644 index d714e30c8cfe2563bf6c25ccd3bd4234ae872768..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 414165 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 z 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%0D@X9bbI( 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 MQqQXo{x+VE|YOr-QcDNM%cay_~x&)MhEu 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 egAJZ~$axm%&xT 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 Date: Mon, 24 Jul 2023 10:53:22 +0800 Subject: [PATCH 06/11] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AD=97=E8=8A=82?= =?UTF-8?q?=E7=A0=81=E5=A2=9E=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../agent/plugin/thread/wrapper/BaseWrapper.java | 4 ++-- .../plugin/thread/wrapper/CallableWrapper.java | 2 +- ...nc-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar | Bin 8285 -> 0 bytes .../main/java/com/example/jasypt/TestJasypt.java | 2 +- .../com/example/controller/TestController.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 cook-async-agent/hippo4j-agent/plugins/cook-async-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/BaseWrapper.java b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/BaseWrapper.java index bb29234c..ed4ec556 100644 --- a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/BaseWrapper.java +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/BaseWrapper.java @@ -6,10 +6,10 @@ import org.slf4j.MDC; import java.util.HashMap; import java.util.Map; -/** +/* * @program: cook-frame * @description: - * @author: k + * @author: 星哥 * @create: 2023-07-21 **/ public class BaseWrapper { diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/CallableWrapper.java b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/CallableWrapper.java index 23945916..fccf1134 100644 --- a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/CallableWrapper.java +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/wrapper/CallableWrapper.java @@ -10,7 +10,7 @@ import java.util.concurrent.Callable; /** * @program: cook-frame * @description: - * @author: k + * @author: 星哥 * @create: 2023-07-21 **/ @AllArgsConstructor diff --git a/cook-async-agent/hippo4j-agent/plugins/cook-async-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar b/cook-async-agent/hippo4j-agent/plugins/cook-async-agent-threadpool-plugin-0.0.1-SNAPSHOT.jar deleted file mode 100644 index 53465dbaf869b2545903b76f6304513d2d58fd9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8285 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 Date: Fri, 28 Jul 2023 10:23:32 +0800 Subject: [PATCH 07/11] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=87=8D=E5=A4=8Dbean?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/balance/ExtraRibbonAutoConfiguration.java | 9 ++++----- .../src/main/java/com/example/filter/FilterConfig.java | 4 ++-- ...ContextFilter.java => RequestParamContextFilter.java} | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) rename threadpool/src/main/java/com/example/filter/{RequestContextFilter.java => RequestParamContextFilter.java} (94%) diff --git a/spring-cloud-extra/service-component/src/main/java/com/example/balance/ExtraRibbonAutoConfiguration.java b/spring-cloud-extra/service-component/src/main/java/com/example/balance/ExtraRibbonAutoConfiguration.java index 60f726b0..01244fdd 100644 --- a/spring-cloud-extra/service-component/src/main/java/com/example/balance/ExtraRibbonAutoConfiguration.java +++ b/spring-cloud-extra/service-component/src/main/java/com/example/balance/ExtraRibbonAutoConfiguration.java @@ -4,7 +4,6 @@ import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration; -import org.springframework.context.annotation.Bean; /** * @program: cook-frame @@ -18,8 +17,8 @@ import org.springframework.context.annotation.Bean; @EnableConfigurationProperties(ExtraRibbonProperties.class) public class ExtraRibbonAutoConfiguration { - @Bean - public CustomEnabledRule discoveryEnabledRule(ExtraRibbonProperties extraRibbonProperties){ - return new CustomEnabledRule(extraRibbonProperties); - } +// @Bean +// public CustomEnabledRule discoveryEnabledRule(ExtraRibbonProperties extraRibbonProperties){ +// return new CustomEnabledRule(extraRibbonProperties); +// } } diff --git a/threadpool/src/main/java/com/example/filter/FilterConfig.java b/threadpool/src/main/java/com/example/filter/FilterConfig.java index dc1680d3..c50b2977 100644 --- a/threadpool/src/main/java/com/example/filter/FilterConfig.java +++ b/threadpool/src/main/java/com/example/filter/FilterConfig.java @@ -12,7 +12,7 @@ import org.springframework.web.filter.OncePerRequestFilter; public class FilterConfig { @Bean - public OncePerRequestFilter requestContextFilter(){ - return new RequestContextFilter(); + public OncePerRequestFilter requestParamContextFilter(){ + return new RequestParamContextFilter(); } } diff --git a/threadpool/src/main/java/com/example/filter/RequestContextFilter.java b/threadpool/src/main/java/com/example/filter/RequestParamContextFilter.java similarity index 94% rename from threadpool/src/main/java/com/example/filter/RequestContextFilter.java rename to threadpool/src/main/java/com/example/filter/RequestParamContextFilter.java index 8bebaa9c..07f0e5ed 100644 --- a/threadpool/src/main/java/com/example/filter/RequestContextFilter.java +++ b/threadpool/src/main/java/com/example/filter/RequestParamContextFilter.java @@ -20,7 +20,7 @@ import static com.example.constant.Constant.TRACE_ID; * @create: 2022-11-08 16:48 **/ -public class RequestContextFilter extends OncePerRequestFilter { +public class RequestParamContextFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (request != null) { -- Gitee From 2163ab85ea1f5e46924eb59b5c9b2e9d8dbfe4fc Mon Sep 17 00:00:00 2001 From: shining-stars-lk <1031900093@qq.com> Date: Sat, 29 Jul 2023 15:43:07 +0800 Subject: [PATCH 08/11] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/department-service/pom.xml | 18 ++++++++++++++++++ server/employee-service/pom.xml | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/server/department-service/pom.xml b/server/department-service/pom.xml index 543848b3..045b3d5b 100644 --- a/server/department-service/pom.xml +++ b/server/department-service/pom.xml @@ -132,6 +132,24 @@ com.alibaba.csp sentinel-datasource-nacos + + + com.example + cook-patch-plugin-register-center-starter-nacos + ${revision} + + + + com.example + cook-patch-plugin-config-center-starter-nacos + ${revision} + + + + com.example + cook-patch-plugin-strategy-starter-service + ${revision} + diff --git a/server/employee-service/pom.xml b/server/employee-service/pom.xml index 92b8e0c9..5ab80d3a 100644 --- a/server/employee-service/pom.xml +++ b/server/employee-service/pom.xml @@ -123,6 +123,24 @@ com.alibaba.csp sentinel-datasource-nacos + + + com.example + cook-patch-plugin-register-center-starter-nacos + ${revision} + + + + com.example + cook-patch-plugin-config-center-starter-nacos + ${revision} + + + + com.example + cook-patch-plugin-strategy-starter-service + ${revision} + -- Gitee From 05144950b5bb02dedae604e5cf54557d7de3b579 Mon Sep 17 00:00:00 2001 From: shining-stars-lk <1031900093@qq.com> Date: Tue, 1 Aug 2023 22:08:09 +0800 Subject: [PATCH 09/11] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ThreadPoolExecuteMethodInterceptor.java | 5 ++ .../ThreadPoolSubmitMethodInterceptor.java | 7 +++ .../thread/enhance/ServiceRequestEnhance.java | 55 +++++++++++++++++++ .../ServiceRequestEnhanceOperation.java | 15 +++++ 4 files changed, 82 insertions(+) create mode 100644 cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/enhance/ServiceRequestEnhance.java create mode 100644 cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/enhance/ServiceRequestEnhanceOperation.java diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolExecuteMethodInterceptor.java b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolExecuteMethodInterceptor.java index cfa16c21..be9bf789 100644 --- a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolExecuteMethodInterceptor.java +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolExecuteMethodInterceptor.java @@ -19,6 +19,7 @@ package com.example.agent.plugin.thread; +import com.example.agent.plugin.thread.enhance.ServiceRequestEnhanceOperation; import com.example.agent.plugin.thread.wrapper.RunnableWrapper; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; @@ -44,6 +45,10 @@ public class ThreadPoolExecuteMethodInterceptor extends AbstractThreadingPoolInt Map contextForTask = getContextForTask(); Map contextForHold = getContextForHold(); RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + if (requestAttributes != null) { + requestAttributes = ServiceRequestEnhanceOperation.enhanceRequestAttributes(requestAttributes); + } + return new RunnableWrapper(runnable,contextForTask,contextForHold,requestAttributes); } return param; diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolSubmitMethodInterceptor.java b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolSubmitMethodInterceptor.java index b4e980b2..3e861730 100644 --- a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolSubmitMethodInterceptor.java +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/ThreadPoolSubmitMethodInterceptor.java @@ -19,6 +19,7 @@ package com.example.agent.plugin.thread; +import com.example.agent.plugin.thread.enhance.ServiceRequestEnhanceOperation; import com.example.agent.plugin.thread.wrapper.CallableWrapper; import com.example.agent.plugin.thread.wrapper.RunnableWrapper; import org.springframework.web.context.request.RequestAttributes; @@ -39,6 +40,9 @@ public class ThreadPoolSubmitMethodInterceptor extends AbstractThreadingPoolInte Map contextForTask = getContextForTask(); Map contextForHold = getContextForHold(); RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + if (requestAttributes != null) { + requestAttributes = ServiceRequestEnhanceOperation.enhanceRequestAttributes(requestAttributes); + } return new CallableWrapper(callable,contextForTask,contextForHold,requestAttributes); } if (param instanceof Runnable) { @@ -46,6 +50,9 @@ public class ThreadPoolSubmitMethodInterceptor extends AbstractThreadingPoolInte Map contextForTask = getContextForTask(); Map contextForHold = getContextForHold(); RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + if (requestAttributes != null) { + requestAttributes = ServiceRequestEnhanceOperation.enhanceRequestAttributes(requestAttributes); + } return new RunnableWrapper(runnable,contextForTask,contextForHold,requestAttributes); } return null; diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/enhance/ServiceRequestEnhance.java b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/enhance/ServiceRequestEnhance.java new file mode 100644 index 00000000..8e4f3896 --- /dev/null +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/enhance/ServiceRequestEnhance.java @@ -0,0 +1,55 @@ +package com.example.agent.plugin.thread.enhance; + + +import org.springframework.util.CollectionUtils; +import org.springframework.util.LinkedCaseInsensitiveMap; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; + +public class ServiceRequestEnhance extends HttpServletRequestWrapper { + private Map> headerMap; + + public ServiceRequestEnhance(HttpServletRequest request) { + super(request); + + headerMap = operateHeaders(request); + } + + private Map> operateHeaders(HttpServletRequest request) { + // 不区分大小写Key的Map用于适配不同的Web容器对于大小写Header的不同处理逻辑 + Map> headers = new LinkedCaseInsensitiveMap>(); + Enumeration headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String headerName = headerNames.nextElement(); + if (headerName != null) { + headers.put(headerName, Collections.list(request.getHeaders(headerName))); + } + } + + return headers; + } + + @Override + public String getHeader(String name) { + List headerValues = headerMap.get(name); + + return CollectionUtils.isEmpty(headerValues) ? null : headerValues.get(0); + } + + @Override + public Enumeration getHeaders(String name) { + List headerValues = headerMap.get(name); + + return Collections.enumeration(headerValues != null ? headerValues : Collections.emptySet()); + } + + @Override + public Enumeration getHeaderNames() { + return Collections.enumeration(headerMap.keySet()); + } +} \ No newline at end of file diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/enhance/ServiceRequestEnhanceOperation.java b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/enhance/ServiceRequestEnhanceOperation.java new file mode 100644 index 00000000..66f2086d --- /dev/null +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/enhance/ServiceRequestEnhanceOperation.java @@ -0,0 +1,15 @@ +package com.example.agent.plugin.thread.enhance; + + +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; + +public class ServiceRequestEnhanceOperation { + public static RequestAttributes enhanceRequestAttributes(RequestAttributes requestAttributes) { + HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); + + return new ServletRequestAttributes(new ServiceRequestEnhance(request)); + } +} \ No newline at end of file -- Gitee From fd0a4f330dff73a017677859aabfba266c924080 Mon Sep 17 00:00:00 2001 From: shining-stars-lk <1031900093@qq.com> Date: Wed, 2 Aug 2023 09:57:56 +0800 Subject: [PATCH 10/11] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../agent/plugin/thread/enhance/ServiceRequestEnhance.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/enhance/ServiceRequestEnhance.java b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/enhance/ServiceRequestEnhance.java index 8e4f3896..8e53fb0d 100644 --- a/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/enhance/ServiceRequestEnhance.java +++ b/cook-async-agent/cook-async-agent-plugin/cook-async-agent-threadpool-plugin/src/main/java/com/example/agent/plugin/thread/enhance/ServiceRequestEnhance.java @@ -21,8 +21,8 @@ public class ServiceRequestEnhance extends HttpServletRequestWrapper { } private Map> operateHeaders(HttpServletRequest request) { - // 不区分大小写Key的Map用于适配不同的Web容器对于大小写Header的不同处理逻辑 - Map> headers = new LinkedCaseInsensitiveMap>(); + // 不区分大小写的Key的Map + Map> headers = new LinkedCaseInsensitiveMap<>(); Enumeration headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String headerName = headerNames.nextElement(); -- Gitee From b41b4983566b5f2526b8239b2729cc70a1ddc498 Mon Sep 17 00:00:00 2001 From: shining-stars-lk <1031900093@qq.com> Date: Wed, 2 Aug 2023 14:06:34 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/department-service/pom.xml | 6 +++--- server/employee-service/pom.xml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/server/department-service/pom.xml b/server/department-service/pom.xml index 045b3d5b..13fcefa8 100644 --- a/server/department-service/pom.xml +++ b/server/department-service/pom.xml @@ -135,19 +135,19 @@ com.example - cook-patch-plugin-register-center-starter-nacos + cook-patch-register-nacos-starter ${revision} com.example - cook-patch-plugin-config-center-starter-nacos + cook-patch-config-nacos-starter ${revision} com.example - cook-patch-plugin-strategy-starter-service + cook-patch-work-service-starter ${revision} diff --git a/server/employee-service/pom.xml b/server/employee-service/pom.xml index 5ab80d3a..354dabc0 100644 --- a/server/employee-service/pom.xml +++ b/server/employee-service/pom.xml @@ -126,19 +126,19 @@ com.example - cook-patch-plugin-register-center-starter-nacos + cook-patch-register-nacos-starter ${revision} com.example - cook-patch-plugin-config-center-starter-nacos + cook-patch-config-nacos-starter ${revision} com.example - cook-patch-plugin-strategy-starter-service + cook-patch-work-service-starter ${revision} -- Gitee