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 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@
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;
Expand All @@ -33,36 +30,24 @@

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

public class CaffeineInterceptor implements InstanceMethodsAroundInterceptor {
abstract public class AbstractCaffeineInterceptor 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();
protected AbstractSpan generateSpanInfo(String methodName) {
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) {
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);
return span;
}

@Override
public void beforeMethod(final EnhancedInstance objInst,
final Method method,
final Object[] allArguments,
final Class<?>[] argumentsTypes,
final MethodInterceptResult result) throws Throwable {
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -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 org.apache.skywalking.apm.plugin.caffeine.v3;

import java.lang.reflect.Method;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
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.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;

public class CaffeineIterableInterceptor extends AbstractCaffeineInterceptor {

@Override
public void beforeMethod(final EnhancedInstance objInst,
final Method method,
final Object[] allArguments,
final Class<?>[] argumentsTypes,
final MethodInterceptResult result) throws Throwable {
AbstractSpan span = generateSpanInfo(method.getName());
if (allArguments != null && allArguments.length > 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary? In which case, allArguments is unexpected?

Copy link
Contributor Author

@CodePrometheus CodePrometheus Dec 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to add judgment, not sure all inputs meet the expectations before this function is processed by upstream.

String keys = StreamSupport
.stream(((Iterable<?>) allArguments[0]).spliterator(), false)
.map(String::valueOf)
.collect(Collectors.joining(","));
Tags.CACHE_KEY.set(span, keys);
}
}
}
Original file line number Diff line number Diff line change
@@ -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 org.apache.skywalking.apm.plugin.caffeine.v3;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.stream.Collectors;
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.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;

public class CaffeineMapInterceptor extends AbstractCaffeineInterceptor {

@Override
public void beforeMethod(final EnhancedInstance objInst,
final Method method,
final Object[] allArguments,
final Class<?>[] argumentsTypes,
final MethodInterceptResult result) throws Throwable {
AbstractSpan span = generateSpanInfo(method.getName());
if (allArguments != null && allArguments.length > 0) {
String keys = ((Map<?, ?>) allArguments[0])
.keySet().stream().map(String::valueOf)
.collect(Collectors.joining(","));
Tags.CACHE_KEY.set(span, keys);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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 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.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;

public class CaffeineStringInterceptor extends AbstractCaffeineInterceptor {

@Override
public void beforeMethod(final EnhancedInstance objInst,
final Method method,
final Object[] allArguments,
final Class<?>[] argumentsTypes,
final MethodInterceptResult result) throws Throwable {
AbstractSpan span = generateSpanInfo(method.getName());
if (allArguments != null && allArguments.length > 0 && allArguments[0] instanceof String) {
Tags.CACHE_KEY.set(span, allArguments[0].toString());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

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

import java.util.Map;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
Expand All @@ -26,14 +27,17 @@
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;

import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
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";
public static final String CAFFEINE_ITERABLE_ENHANCE_CLASS = "org.apache.skywalking.apm.plugin.caffeine.v3.CaffeineIterableInterceptor";
public static final String CAFFEINE_MAP_ENHANCE_CLASS = "org.apache.skywalking.apm.plugin.caffeine.v3.CaffeineMapInterceptor";
public static final String CAFFEINE_STRING_ENHANCE_CLASS = "org.apache.skywalking.apm.plugin.caffeine.v3.CaffeineStringInterceptor";

// read/write operations
public static final String GET_IF_PRESENT_METHOD = "getIfPresent";
Expand All @@ -48,7 +52,7 @@ public class CaffeineInstrumentation extends ClassInstanceMethodsEnhancePluginDe
protected ClassMatch enhanceClass() {
return byMultiClassMatch(BOUNDED_LOCAL_INTERCEPT_CLASS, UNBOUNDED_LOCAL_INTERCEPT_CLASS);
}

@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
Expand All @@ -62,17 +66,47 @@ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
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;
return CAFFEINE_STRING_ENHANCE_CLASS;
}

@Override
public boolean isOverrideArgs() {
return false;
}
},
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named(GET_ALL_PRESENT_METHOD).and(takesArgument(0, Iterable.class));
}

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

@Override
public boolean isOverrideArgs() {
return false;
}
},
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named(PUT_ALL_METHOD).and(takesArgument(0, Map.class));
}

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

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ segmentItems:
spanType: Local
peer: ''
tags:
- { key: cache.key, value: "1" }
- { key: cache.type, value: Caffeine }
- { key: cache.cmd, value: put }
- { key: cache.op, value: write }
- { key: cache.key, value: "1" }
skipAnalysis: 'false'
- operationName: Caffeine/putAll
parentSpanId: 0
Expand All @@ -47,10 +47,10 @@ segmentItems:
spanType: Local
peer: ''
tags:
- { key: cache.key, value: "2" }
- { key: cache.type, value: Caffeine }
- { key: cache.cmd, value: putAll }
- { key: cache.op, value: write }
- { key: cache.key, value: "2" }
skipAnalysis: 'false'
- operationName: Caffeine/computeIfAbsent
parentSpanId: 0
Expand All @@ -63,10 +63,10 @@ segmentItems:
spanType: Local
peer: ''
tags:
- { key: cache.key, value: "1" }
- { key: cache.type, value: Caffeine }
- { key: cache.cmd, value: computeIfAbsent }
- { key: cache.op, value: read }
- { key: cache.key, value: "1" }
- operationName: Caffeine/getIfPresent
parentSpanId: 0
spanId: 4
Expand All @@ -78,10 +78,10 @@ segmentItems:
spanType: Local
peer: ''
tags:
- { key: cache.key, value: "1" }
- { key: cache.type, value: Caffeine }
- { key: cache.cmd, value: getIfPresent }
- { key: cache.op, value: read }
- { key: cache.key, value: "1" }
skipAnalysis: 'false'
- operationName: Caffeine/getAllPresent
parentSpanId: 0
Expand All @@ -95,10 +95,10 @@ segmentItems:
peer: ''
skipAnalysis: 'false'
tags:
- { key: cache.key, value: '2' }
- { key: cache.type, value: Caffeine }
- { key: cache.cmd, value: getAllPresent }
- { key: cache.op, value: read }
- { key: cache.key, value: '2' }
- operationName: Caffeine/remove
parentSpanId: 0
spanId: 6
Expand All @@ -111,10 +111,10 @@ segmentItems:
peer: ''
skipAnalysis: 'false'
tags:
- { key: cache.key, value: '1' }
- { key: cache.type, value: Caffeine }
- { key: cache.cmd, value: remove }
- { key: cache.op, value: write }
- { key: cache.key, value: '1' }
- operationName: Caffeine/remove
parentSpanId: 0
spanId: 7
Expand All @@ -127,10 +127,10 @@ segmentItems:
peer: ''
skipAnalysis: 'false'
tags:
- { key: cache.key, value: '2' }
- { key: cache.type, value: Caffeine }
- { key: cache.cmd, value: remove }
- { key: cache.op, value: write }
- { key: cache.key, value: '2' }
- operationName: Caffeine/clear
parentSpanId: 0
spanId: 8
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@
@RestController
public class CaffeineController {

Cache<Object, Object> caffeine = Caffeine.newBuilder().build();

@GetMapping("/case/caffeine")
public void testCase() {
try {
Cache<Object, Object> caffeine = Caffeine.newBuilder().build();
Map<String, String> data = new HashMap<>();
data.put("2", "value-2");

Expand Down
Loading