Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Caffeine plugin as optional #743

Merged
merged 5 commits into from
Dec 29, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
build:
name: Java ${{ matrix.java-version }} / ${{ matrix.os }}
runs-on: ${{ matrix.os }}-latest
timeout-minutes: 60
timeout-minutes: 90
needs: [ license ]
strategy:
fail-fast: true
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeql.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ jobs:
java-version: 17

- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}

- run: ./mvnw -q -Dmaven.test.skip=true clean install || ./mvnw -q -Dmaven.test.skip=true clean install

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v3
1 change: 1 addition & 0 deletions .github/workflows/plugins-jdk17-test.1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ jobs:
- c3p0-0.9.0.x-0.9.1.x-scenario
- c3p0-0.9.2.x-0.10.x-scenario
- spring-scheduled-6.x-scenario
- caffeine-3.x-scenario
wu-sheng marked this conversation as resolved.
Show resolved Hide resolved
steps:
- uses: actions/checkout@v2
with:
Expand Down
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Release Notes.
Plugin, Kotlin Coroutine Plugin, and Spring Gateway Plugin
* Change context and parent entry span propagation mechanism from gRPC ThreadLocal context to SkyWalking native dynamic
field as new propagation mechanism, to better support async scenarios.
* Add Caffeine plugin as optional.

All issues and pull requests are [here](https://github.com/apache/skywalking/milestone/222?closed=1)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,4 +259,5 @@ public class ComponentsDefine {

public static final OfficialComponent SOLON_MVC = new OfficialComponent(158, "SolonMVC");

public static final OfficialComponent CAFFEINE = new OfficialComponent(160, "Caffeine");
}
4 changes: 4 additions & 0 deletions apm-sniffer/config/agent.config
Original file line number Diff line number Diff line change
Expand Up @@ -332,3 +332,7 @@ plugin.solon.http_params_length_threshold=${SW_PLUGIN_SOLON_HTTP_PARAMS_LENGTH_T
plugin.solon.include_http_headers=${SW_PLUGIN_SOLON_INCLUDE_HTTP_HEADERS:}
# Define the max length of collected HTTP body. The default value(=0) means not collecting.
plugin.solon.http_body_length_threshold=${SW_PLUGIN_SOLON_HTTP_BODY_LENGTH_THRESHOLD:0}
# Specify which command should be converted to write operation
plugin.caffeine.operation_mapping_write=${SW_PLUGIN_CAFFEINE_OPERATION_MAPPING_WRITE:put,putAll,remove,clear}
# Specify which command should be converted to read operation
plugin.caffeine.operation_mapping_read=${SW_PLUGIN_CAFFEINE_OPERATION_MAPPING_READ:getIfPresent,getAllPresent,computeIfAbsent}
46 changes: 46 additions & 0 deletions apm-sniffer/optional-plugins/caffeine-3.x-plugin/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.skywalking</groupId>
<artifactId>optional-plugins</artifactId>
<version>9.4.0-SNAPSHOT</version>
</parent>

<artifactId>apm-caffeine-3.x-plugin</artifactId>
<packaging>jar</packaging>
<name>caffeine-3.x-plugin</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<caffeine.version>3.1.8</caffeine.version>
</properties>

<dependencies>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>${caffeine.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -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 org.apache.skywalking.apm.plugin.caffeine.v3;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;

import static org.apache.skywalking.apm.plugin.caffeine.v3.CaffeineOperationTransform.transformOperation;

public class CaffeineInterceptor implements InstanceMethodsAroundInterceptor {

@Override
public void beforeMethod(final EnhancedInstance objInst,
final Method method,
final Object[] allArguments,
final Class<?>[] argumentsTypes,
final MethodInterceptResult result) throws Throwable {
String methodName = method.getName();
AbstractSpan span = ContextManager.createLocalSpan("Caffeine/" + methodName);
span.setComponent(ComponentsDefine.CAFFEINE);
if (allArguments != null && allArguments.length > 0 && allArguments[0] != null) {
if (allArguments[0] instanceof String) {
Tags.CACHE_KEY.set(span, allArguments[0].toString());
} else if (allArguments[0] instanceof Map) {
String keys = ((Map<?, ?>) allArguments[0])
.keySet().stream().map(String::valueOf)
.collect(Collectors.joining(","));
Tags.CACHE_KEY.set(span, keys);
} else if (allArguments[0] instanceof Set) {
wu-sheng marked this conversation as resolved.
Show resolved Hide resolved
String keys = ((Set<?>) allArguments[0])
.stream().map(String::valueOf)
.collect(Collectors.joining(","));
Tags.CACHE_KEY.set(span, keys);
}
}
Tags.CACHE_TYPE.set(span, ComponentsDefine.CAFFEINE.getName());
Tags.CACHE_CMD.set(span, methodName);
transformOperation(methodName).ifPresent(op -> Tags.CACHE_OP.set(span, op));
SpanLayer.asCache(span);
}

@Override
public Object afterMethod(final EnhancedInstance objInst,
final Method method,
final Object[] allArguments,
final Class<?>[] argumentsTypes,
final Object ret) throws Throwable {
ContextManager.stopSpan();
return ret;
}

@Override
public void handleMethodException(final EnhancedInstance objInst,
final Method method,
final Object[] allArguments,
final Class<?>[] argumentsTypes,
final Throwable t) {
ContextManager.activeSpan().log(t);
}
}
Original file line number Diff line number Diff line change
@@ -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 org.apache.skywalking.apm.plugin.caffeine.v3;

import java.util.Optional;

public class CaffeineOperationTransform {

public static Optional<String> transformOperation(String cmd) {
if (CaffeinePluginConfig.Plugin.Caffeine.OPERATION_MAPPING_READ.contains(cmd)) {
return Optional.of("read");
}
if (CaffeinePluginConfig.Plugin.Caffeine.OPERATION_MAPPING_WRITE.contains(cmd)) {
return Optional.of("write");
}
return Optional.empty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package org.apache.skywalking.apm.plugin.caffeine.v3;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.apache.skywalking.apm.agent.core.boot.PluginConfig;

/**
* Operation represent a cache span is "write" or "read" action , and "op"(operation) is tagged with key "cache.op"
* usually This config term define which command should be converted to write Operation .
*
* @see org.apache.skywalking.apm.agent.core.context.tag.Tags#CACHE_OP
* @see CaffeineOperationTransform#transformOperation(String)
*/
public class CaffeinePluginConfig {
public static class Plugin {
@PluginConfig(root = CaffeinePluginConfig.class)
public static class Caffeine {
public static Set<String> OPERATION_MAPPING_WRITE = new HashSet<>(Arrays.asList(
"put",
"putAll",
"remove",
"clear"
));
public static Set<String> OPERATION_MAPPING_READ = new HashSet<>(Arrays.asList(
"getIfPresent",
"getAllPresent",
"computeIfAbsent"
));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package org.apache.skywalking.apm.plugin.caffeine.v3.define;

import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;

import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import static org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch.byMultiClassMatch;

public class CaffeineInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {

public static final String BOUNDED_LOCAL_INTERCEPT_CLASS = "com.github.benmanes.caffeine.cache.BoundedLocalCache";
public static final String UNBOUNDED_LOCAL_INTERCEPT_CLASS = "com.github.benmanes.caffeine.cache.UnboundedLocalCache";
public static final String CAFFEINE_ENHANCE_CLASS = "org.apache.skywalking.apm.plugin.caffeine.v3.CaffeineInterceptor";

// read/write operations
public static final String GET_IF_PRESENT_METHOD = "getIfPresent";
public static final String GET_ALL_PRESENT_METHOD = "getAllPresent";
public static final String COMPUTE_IF_ABSENT_METHOD = "computeIfAbsent";
public static final String PUT_METHOD = "put";
public static final String PUT_ALL_METHOD = "putAll";
public static final String REMOVE_METHOD = "remove";
public static final String CLEAR_METHOD = "clear";

@Override
protected ClassMatch enhanceClass() {
return byMultiClassMatch(BOUNDED_LOCAL_INTERCEPT_CLASS, UNBOUNDED_LOCAL_INTERCEPT_CLASS);
}

@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}

@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[] {
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named(GET_IF_PRESENT_METHOD)
.and(takesArguments(2))
.or(named(GET_ALL_PRESENT_METHOD).and(takesArguments(1)))
.or(named(COMPUTE_IF_ABSENT_METHOD).and(takesArguments(4)))
.or(named(PUT_METHOD).and(takesArguments(2)))
.or(named(REMOVE_METHOD).and(takesArguments(1)))
.or(named(PUT_ALL_METHOD).and(takesArguments(1)))
.or(named(CLEAR_METHOD).and(takesArguments(0)));
}

@Override
public String getMethodsInterceptor() {
return CAFFEINE_ENHANCE_CLASS;
}

@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}
Original file line number Diff line number Diff line change
@@ -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.

caffeine-3.x=org.apache.skywalking.apm.plugin.caffeine.v3.define.CaffeineInstrumentation
Loading
Loading