-
Notifications
You must be signed in to change notification settings - Fork 45
Update nocode instrumentation #2294
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
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| /* | ||
| * Copyright Splunk Inc. | ||
| * | ||
| * 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. | ||
| */ | ||
|
|
||
| package com.splunk.opentelemetry.javaagent.bootstrap.nocode; | ||
|
|
||
| public interface NocodeExpression { | ||
|
|
||
| Object evaluate(Object thiz, Object[] params); | ||
|
|
||
| Object evaluateAtEnd(Object thiz, Object[] params, Object returnValue, Throwable error); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,7 +16,7 @@ | |
|
|
||
| package com.splunk.opentelemetry.instrumentation.nocode; | ||
|
|
||
| import com.splunk.opentelemetry.javaagent.bootstrap.nocode.NocodeEvaluation; | ||
| import com.splunk.opentelemetry.javaagent.bootstrap.nocode.NocodeExpression; | ||
| import io.opentelemetry.api.common.AttributesBuilder; | ||
| import io.opentelemetry.context.Context; | ||
| import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesExtractor; | ||
|
|
@@ -25,8 +25,7 @@ | |
| import java.util.Map; | ||
| import javax.annotation.Nullable; | ||
|
|
||
| public final class NocodeAttributesExtractor | ||
| implements AttributesExtractor<NocodeMethodInvocation, Object> { | ||
| class NocodeAttributesExtractor implements AttributesExtractor<NocodeMethodInvocation, Object> { | ||
| private final AttributesExtractor<ClassAndMethod, Object> codeExtractor; | ||
|
|
||
| public NocodeAttributesExtractor() { | ||
|
|
@@ -38,10 +37,10 @@ public void onStart( | |
| AttributesBuilder attributesBuilder, Context context, NocodeMethodInvocation mi) { | ||
| codeExtractor.onStart(attributesBuilder, context, mi.getClassAndMethod()); | ||
|
|
||
| Map<String, String> attributes = mi.getRuleAttributes(); | ||
| Map<String, NocodeExpression> attributes = mi.getRuleAttributes(); | ||
| for (String key : attributes.keySet()) { | ||
| String expression = attributes.get(key); | ||
| Object value = NocodeEvaluation.evaluate(expression, mi.getThiz(), mi.getParameters()); | ||
| NocodeExpression expression = attributes.get(key); | ||
|
||
| Object value = mi.evaluate(expression); | ||
| if (value instanceof Long | ||
| || value instanceof Integer | ||
| || value instanceof Short | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,6 +24,7 @@ | |
| import com.splunk.opentelemetry.javaagent.bootstrap.nocode.NocodeRules; | ||
| import io.opentelemetry.context.Context; | ||
| import io.opentelemetry.context.Scope; | ||
| import io.opentelemetry.instrumentation.api.annotation.support.async.AsyncOperationEndSupport; | ||
| import io.opentelemetry.instrumentation.api.incubator.semconv.util.ClassAndMethod; | ||
| import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; | ||
| import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; | ||
|
|
@@ -32,6 +33,7 @@ | |
| import net.bytebuddy.description.type.TypeDescription; | ||
| import net.bytebuddy.implementation.bytecode.assign.Assigner; | ||
| import net.bytebuddy.matcher.ElementMatcher; | ||
| import net.bytebuddy.utility.JavaConstant; | ||
|
|
||
| public final class NocodeInstrumentation implements TypeInstrumentation { | ||
| private final NocodeRules.Rule rule; | ||
|
|
@@ -42,32 +44,45 @@ public NocodeInstrumentation(NocodeRules.Rule rule) { | |
|
|
||
| @Override | ||
| public ElementMatcher<TypeDescription> typeMatcher() { | ||
| // names have to match exactly for now to enable rule lookup | ||
| // at advice time. In the future, we could support | ||
| // more complex rules here if we dynamically generated advice classes for | ||
| // each rule. | ||
| return rule != null ? named(rule.className) : none(); | ||
| // null rule is used when no rules are configured, this ensures that muzzle can collect helper | ||
| // classes | ||
| return rule != null ? named(rule.getClassName()) : none(); | ||
| } | ||
|
|
||
| @Override | ||
| public void transform(TypeTransformer transformer) { | ||
| transformer.applyAdviceToMethod( | ||
| rule != null ? named(rule.methodName) : none(), | ||
| rule != null ? named(rule.getMethodName()) : none(), | ||
| mapping -> | ||
| mapping | ||
| .bind(RuleId.class, JavaConstant.Simple.ofLoaded(rule != null ? rule.getId() : -1)) | ||
| .bind( | ||
| MethodReturnType.class, | ||
| (instrumentedType, instrumentedMethod, assigner, argumentHandler, sort) -> | ||
| Advice.OffsetMapping.Target.ForStackManipulation.of( | ||
| instrumentedMethod.getReturnType().asErasure())), | ||
| this.getClass().getName() + "$NocodeAdvice"); | ||
| } | ||
|
|
||
| // custom annotation that allows looking up the rule that triggered instrumenting the method | ||
| @interface RuleId {} | ||
|
|
||
| // custom annotation that represents the return type of the method | ||
| @interface MethodReturnType {} | ||
|
|
||
| @SuppressWarnings("unused") | ||
| public static class NocodeAdvice { | ||
| @Advice.OnMethodEnter(suppress = Throwable.class) | ||
| public static void onEnter( | ||
| @RuleId int ruleId, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎉 ! |
||
| @Advice.Origin("#t") Class<?> declaringClass, | ||
| @Advice.Origin("#m") String methodName, | ||
| @Advice.Local("otelInvocation") NocodeMethodInvocation otelInvocation, | ||
| @Advice.Local("otelContext") Context context, | ||
| @Advice.Local("otelScope") Scope scope, | ||
| @Advice.This Object thiz, | ||
| @Advice.AllArguments Object[] methodParams) { | ||
| NocodeRules.Rule rule = NocodeRules.find(declaringClass.getName(), methodName); | ||
| NocodeRules.Rule rule = NocodeRules.find(ruleId); | ||
| otelInvocation = | ||
| new NocodeMethodInvocation( | ||
| rule, ClassAndMethod.create(declaringClass, methodName), thiz, methodParams); | ||
|
|
@@ -86,16 +101,16 @@ public static void stopSpan( | |
| @Advice.Local("otelInvocation") NocodeMethodInvocation otelInvocation, | ||
| @Advice.Local("otelContext") Context context, | ||
| @Advice.Local("otelScope") Scope scope, | ||
| @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returnValue, | ||
| @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object returnValue, | ||
| @Advice.Thrown Throwable error) { | ||
| if (scope == null) { | ||
| return; | ||
| } | ||
| scope.close(); | ||
| // This is heavily based on the "methods" instrumentation from upstream, but | ||
| // for now we're not supporting modifying return types/async result codes, etc. | ||
| // This could be expanded in the future. | ||
| instrumenter().end(context, otelInvocation, returnValue, error); | ||
|
|
||
| returnValue = | ||
| AsyncOperationEndSupport.create(instrumenter(), Object.class, method.getReturnType()) | ||
| .asyncEnd(context, otelInvocation, returnValue, error); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very happy about this! |
||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.