-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
[pkg/ottl] Add conflict resolution strategies for set
#31808
Comments
Pinging code owners:
See Adding Labels via Comments if you do not have permissions to add labels yourself. |
I like this idea, although we'll need to me sure we clearly define what I'd like to align the names with the attribute processor's: |
with the PoC i have for this i was playing with idea of checking nil as you said. for otlp fields i have a question though. empty string check is fairly easy and i don't think setting field to empty string is something done on purpose. what about other types numbers, bools. What's the behavior there? Can it happen that these are present and set to default values (0, false)? or would these also default to ""? |
Yes this will definitely be a problem. There are fields like |
i will try to play with these to figure out what the proper solution should be. but i can see that with |
Playing with different fields today and yes, for some number/boolean fields it's most likely impossible to tell whether value is valid or default. i see empty string values are usually uninitialized (missing) so i was thinking about handling default value for number/boolean as not missing. user when working with transformations, specifying a field to be set should be field aware and can make best decision. i'd love to hear your thoughts. maybe I'm trying to make it unnecessary complicated and not user friendly |
As you say, we'd stick with |
One thing to consider: both
@evan-bradley what are your thoughts. |
@michalpristas since the
Can you expand some more on the |
for otherwise i'm fine with suggestions |
Can I take this up @TylerHelmuth @michalpristas ? |
@kernelpanic77 we're still discussing if we need this feature or if the Where clause is sufficient. We need to answer the questions from #31808 (comment). For For Normally adding an optional parameter would be no problem bc it is optional, but the |
i agree, for me when i looked into ottl functions i did not even know that there is a possibility to do where statements. so for first time users having explicit arguments may play out well. we were talking in case of missing, attributes are easy, it is nil check. the same as with where statements I'm just trying to have this user in mind. |
This is not the first time I've heard this 😞 OTTL docs and discoverability need some love.
Very true, thats a really good argument for adding this feature. |
Sorry for the long delay. In general, I'm a fan of the "one correct way to do things" approach where we keep things as consistent as possible and try to build on existing patterns to help users solve problems. I feel like it makes the language more predictable. I think this feature is good to consider, but my gut feeling is that we should continue to rely on where clauses. I have a few points supporting this:
That said, there are a few points in favor of this feature:
I'm not going to suggest closing this issue, but before we implement it, I would like to see feedback from others that this is something they would like to see. Thanks @michalpristas for the detailed issue and input on this proposal. |
This issue has been inactive for 60 days. It will be closed in 60 days if there is no activity. To ping code owners by adding a component label, see Adding Labels via Comments, or if you are unsure of which component this issue relates to, please ping Pinging code owners:
See Adding Labels via Comments if you do not have permissions to add labels yourself. |
As an end user, the strategy parameter would be confusing to me. This is obviously a subjective, personal opinion. What would be easy to understand in my opinion is to have separate functions implementing different strategies:
|
@michalpristas Is this issue still relevant even if #31901 is closed? |
@andrzej-stencel Thanks for the input. How do you think separate functions compare to using OTTL's where clauses to achieve equivalent functionality? |
If I understand correctly, the following statements would be equivalent (as already mentioned above in this thread):
Looking at this, I definitely don't like the additional strategy parameter in the set function, as I think it's hard to read. I think the new strategy functions update(), insert(), insertOrFail() increase the readability a bit. This might be especially noticeable in more complex scenarios. For example, I believe the following:
is easier to read than:
On the other hand, you could argue that the second option is more explicit. I suppose this goes down to a personal preference? 😄 |
can you please assign this to me? |
@michalpristas Assigned, thanks for volunteering. I'd like to hold off on a PR for now until we've confirmed that we would like to add this functionality. @andrzej-stencel Thanks for the input. I'm clearly biased, but I still find the verbosity of the where clauses to be more obvious for what is going on. If I'm reading OTTL statements, it would be immediately obvious to me when @TylerHelmuth what are your thoughts? |
i like what @andrzej-stencel suggested, it allows you to use where clause if you want, but in case you're not that technical, you don't understand inner working and when field is nil or "" it provides you with very clear options |
when i take a look for example pipeline we have here and produce something otel like (not working) we can see clearly that spotting updates is much easier with function calls than with an ocean of where clause. - set(attribute["user.id"], '{{{zoom.operator_id}}}')
- set(attribute["user.email"], '{{{zoom.operator}}}')
- set(attribute["user.id"], '{{{zoom.user.id}}}') where ctx.zoom?.operator == null && ctx.zoom?.operator_id == null
- set(attribute["user.email"], '{{{zoom.user.email}}}') where ctx.zoom?.operator == null && ctx.zoom?.operator_id == null
- set(attribute["user.full_name"], '{{zoom.user.first_name}} {{zoom.user.last_name}}') where ctx.zoom?.operator == null && ctx.zoom?.operator_id == null && ctx.zoom?.user?.first_name != null
- set(attribute["user.target.id"], '{{{zoom.old_values.id}}}')
- set(attribute["user.target.id"], '{{{zoom.old_values.id}}}')
- set(attribute["user.target.email"], '{{{zoom.old_values.email}}}')
- set(attribute["user.target.email"], '{{{zoom.old_values.email}}}')
- set(attribute["user.target.full_name"], '{{zoom.old_values.first_name}} {{zoom.old_values.last_name}}') where ctx.zoom?.old_values?.first_name != null
- set(attribute["user.target.id"], '{{{zoom.user.id}}}') where attribute["user.target.id"] != nil
- set(attribute["user.target.id"], '{{{zoom.user.id}}}') where attribute["user.target.id"] != nil
- set(attribute["user.target.email"], '{{{zoom.user.email}}}') where attribute["user.target.email"] != nil
- set(attribute["user.target.email"], '{{{zoom.user.email}}}') where attribute["user.target.email"] != nil
- set(attribute["user.target.full_name"], '{{zoom.user.first_name}} {{zoom.user.last_name}}') where attribute["user.target.full_name"] != nil
where '(ctx.zoom?.old_values != null || ctx.zoom?.operator != null || ctx.zoom?.operator_id != null) && ctx.zoom?.user?.first_name != null'
- set(attribute["user.changes.id"], '{{{zoom.user.id}}}')
where ctx.zoom?.old_values?.id != null && ctx.zoom?.old_values?.id != ctx.zoom?.user?.id
- set(attribute["user.changes.email"], '{{{zoom.user.email}}}')
where ctx.zoom?.old_values?.email != null && ctx.zoom?.old_values?.email != ctx.zoom?.user?.email
- set(attribute["user.changes.full_name"], '{{zoom.user.first_name}} {{zoom.user.last_name}}')
where ctx.zoom?.old_values?.first_name != null && ctx.zoom?.old_values?.last_name != null && (ctx.zoom?.old_values?.last_name != ctx.zoom?.user?.last_name || ctx.zoom?.old_values?.first_name != ctx.zoom?.user?.first_name)
- set(attribute["event.kind"], pipeline_error) - set(attribute["user.id"], '{{{zoom.operator_id}}}')
- set(attribute["user.email"], '{{{zoom.operator}}}')
- set(attribute["user.id"], '{{{zoom.user.id}}}') where ctx.zoom?.operator == null && ctx.zoom?.operator_id == null
- set(attribute["user.email"], '{{{zoom.user.email}}}') where ctx.zoom?.operator == null && ctx.zoom?.operator_id == null
- set(attribute["user.full_name"], '{{zoom.user.first_name}} {{zoom.user.last_name}}') where ctx.zoom?.operator == null && ctx.zoom?.operator_id == null && ctx.zoom?.user?.first_name != null
- set(attribute["user.target.id"], '{{{zoom.old_values.id}}}')
- set(attribute["user.target.id"], '{{{zoom.old_values.id}}}')
- set(attribute["user.target.email"], '{{{zoom.old_values.email}}}')
- set(attribute["user.target.email"], '{{{zoom.old_values.email}}}')
- set(attribute["user.target.full_name"], '{{zoom.old_values.first_name}} {{zoom.old_values.last_name}}') where ctx.zoom?.old_values?.first_name != null
- update(attribute["user.target.id"], '{{{zoom.user.id}}}')
- update(attribute["user.target.id"], '{{{zoom.user.id}}}')
- update(attribute["user.target.email"], '{{{zoom.user.email}}}')
- update(attribute["user.target.email"], '{{{zoom.user.email}}}')
- update(attribute["user.target.full_name"], '{{zoom.user.first_name}} {{zoom.user.last_name}}')
where '(ctx.zoom?.old_values != null || ctx.zoom?.operator != null || ctx.zoom?.operator_id != null) && ctx.zoom?.user?.first_name != null'
- set(attribute["user.changes.id"], '{{{zoom.user.id}}}')
where ctx.zoom?.old_values?.id != null && ctx.zoom?.old_values?.id != ctx.zoom?.user?.id
- set(attribute["user.changes.email"], '{{{zoom.user.email}}}')
where ctx.zoom?.old_values?.email != null && ctx.zoom?.old_values?.email != ctx.zoom?.user?.email
- set(attribute["user.changes.full_name"], '{{zoom.user.first_name}} {{zoom.user.last_name}}')
where ctx.zoom?.old_values?.first_name != null && ctx.zoom?.old_values?.last_name != null && (ctx.zoom?.old_values?.last_name != ctx.zoom?.user?.last_name || ctx.zoom?.old_values?.first_name != ctx.zoom?.user?.first_name)
- set(attribute["event.kind"], pipeline_error) |
what magic is this |
no worries this is just untranslated condition, i just did a quick fulltext transform to illustrate the case In painless to avoid |
are we in an agreement here and can proceed or should we discuss during SIG or create a poll? |
@michalpristas If you could come to a SIG meeting, I think that would be valuable. If we can't come to an agreement, a poll could also be a good option. |
closing this issue as discussed in SIG. we'll stick with |
Component(s)
pkg/ottl
Is your feature request related to a problem? Please describe.
Related to a rename work here
it would be useful to have the option to specify conflict resolution strategy for
set
as well.Describe the solution you'd like
scenarios i have in mind at the moment are
we would end up with following signature:
set(target, value, [Optional] conflict_resolution_strategy)
Describe alternatives you've considered
No response
Additional context
No response
The text was updated successfully, but these errors were encountered: