Skip to content

Use jexl for nocode expressions#2203

Merged
laurit merged 17 commits intosignalfx:mainfrom
johnbley:nocode_jexl
Feb 28, 2025
Merged

Use jexl for nocode expressions#2203
laurit merged 17 commits intosignalfx:mainfrom
johnbley:nocode_jexl

Conversation

@johnbley
Copy link
Copy Markdown
Contributor

Use jexl (Apache 2.0 license) for nocode expressions. Very little syntax change from the first prototype.

@johnbley johnbley requested review from a team as code owners February 24, 2025 19:22
@johnbley johnbley marked this pull request as draft February 24, 2025 19:22
@johnbley johnbley marked this pull request as ready for review February 24, 2025 20:52
@johnbley johnbley requested a review from a team as a code owner February 24, 2025 20:52
@johnbley johnbley changed the title Use jexl for nocode expressions [DRAFT] Use jexl for nocode expressions Feb 24, 2025
* Please be careful with this, it's directly tied to @Advice.AllArguments.
*
* @return
* @return @Advice.AllArguments - please be careful
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

just curious what concerns did you have to add this warning?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Jason pointed out that this is a mutable array and users of it should take care to know that it is tied to the given advice instrumentation. #2184 (comment)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@Advice.AllArguments takes a parameter readOnly that defaults to true. This parameter controls whether method arguments can be mutated using the returned array. Reading #2184 (comment) I think that Jason was just concerned that array is a mutable type. I wouldn't be too concerned with this.

String evaluate(String expression, Object thiz, Object[] params);
}

private static final AtomicReference<Evaluator> globalEvaluator = new AtomicReference<>();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I probably would have used a volatile variable, but AtomicReference is fine too

context.set("param" + i, params[i]);
}
try {
// could cache the Expression in the Rule if desired
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think this would be a good idea. Wouldn't need to parse the expression for each evaluation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'll do a round of profiling for easy wins later, this will likely jump out as a pretty obvious one.

public final class YamlParser {
private static final Logger logger = Logger.getLogger(YamlParser.class.getName());
// FIXME support method override selection - e.g., with classfile method signature or something
// FUTURE support method override selection - e.g., with classfile method signature or something
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

One issue with instrumenting methods from sub classes is that we currently can't easily tell from advice code which rule is tied to the method invocation because we can't just look up the rule based on the invoked class and method name. I haven't tried it out yet, but I believe we could make this work by adding an api in the upstream that would let us pass extra data, such as rule id, into the invoked advice method.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, I've looked at this and though I can't see how yet, there must be a way to get either something passed into the Advice along these lines, or else have the thing that pastes the bytecode into the instrumented method be parameterized per-instance in some way with a ldc.

return Stream.of(
// Might be nice to support a bare "param0" or "this" but as a workaround can always use
// "this.toString()"
arguments("this", "{key=value}"),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

an alternative to using expressions would be to use templates (I think this is what they are called in jexl) where you have something like Hello ${this.name}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah, jexl has a lot of features; I tried to keep things more java-y than expression-y. When this gets more mature/field-tested I'll add docs for common scenarios, the names of the provided variables, etc.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Unfortunately the behavior is hard to change once this feature is made public so we'll have to consider that we are probably going to be stuck with whatever we come up here for a long time.

@laurit laurit merged commit 4144360 into signalfx:main Feb 28, 2025
26 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Feb 28, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants