-
Notifications
You must be signed in to change notification settings - Fork 51
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
Capability to manually create spans #956
base: main
Are you sure you want to change the base?
Conversation
@kuisathaverat @cyrille-leclerc Can you take a look at this PR? It's related to this issue #90 |
// install() returns a Future for every plugin. Call get() on the Future so that this line blocks | ||
// until the operation is finished and the future is available. | ||
jenkinsRule.jenkins.getPluginManager().install( | ||
Collections.singletonList("durable-task"), true).get(0).get(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without this change, most of the integration tests are failing to start.
@kuisathaverat Did you get a chance to take a look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've just added a comment without reviewing the implementation but the syntax and usability
BTW, thanks so much for your contribution 💯 🙏
withNewSpan(label: 'custom-build-span', attributes: ([ | ||
spanAttribute(key: 'modules', value: '2'), | ||
spanAttribute(key: 'command', value: 'mvn clean install') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity, could this be less verbose as a key and value instead of a spanAttribute object?
Something like the below pseudo-code:
withNewSpan(label: 'custom-build-span', attributes: ([
'modules': '2',
'command': 'mvn clean install'])
The declarative syntax might benefit from a shorter syntax. If users decide to use a bunch of attributes, with the current proposal, there will be 26 chars extra per entry.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @v1v, thanks for the review!
could this be less verbose as a key and value instead of a spanAttribute object?
Not at the moment, but it's doable.
In my current approach, I'm reusing the code for the SpanAttributeStepExecution
and it works the same way as in WithSpanAttributesStep
which has this constructor
@DataBoundConstructor
public WithSpanAttributesStep(List<SpanAttribute> spanAttributes) {
this.spanAttributes = spanAttributes;
}
for that reason, the WithNewSpanStep
also accepts a List<SpanAttribute>
.
Because it's annotated with @DataBoundConstructor
, you can't overload it but if the parameter type changes to Object attributes
, it can also accept a map and that would achieve the behavior that you want. We can convert the map to a List<SpanAttribute>
and keep reusing the existing code.
The question is, do we want to make the change only in WithNewSpanStep
or should we make it in WithSpanAttributesStep
to make the change more global and keep the behavior consistent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did some testing and it turns out that it's not that straight forward. Jenkins doesn't like the type-cast from Object
to a SpanAttribute
element of a List. No issues with using a Map, we can get the values and then create a List<SpanAttribute>
but that will break consistency with the other steps.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @v1v, any thoughts on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Christos for your analysis. It's totally fine
Sorry for not getting back to you sooner, but I did not find time to perform the manual test needed to verify that there are no regressions. Also, I want to make a huge pipeline test to verify there are no leaks or performance issues. |
@kuisathaverat Is there something I can do to help? Run some test? I've run manual tests but my use-cases might not match yours. |
I need more time. I have compared two "similar" pipelines to see if the memory usage grows, and it does. A pipeline with 500 steps uses about 450MB of RAM and does not increase memory usage after it is finished. I executed it 10 times. pipeline {
agent any
stages {
stage('prepare') {
steps {
bunchOfSteps(0)
}
}
}
}
def bunchOfSteps(level) {
if (level < 100) {
sh "echo level ${level}"
bunchOfSteps(level + 1)
}
} A pipeline with 500 steps and the new step to create spans uses about 850MB of RAM and increases the memory usage after it finishes about 350MB. I executed it one time. pipeline {
agent any
stages {
stage('prepare') {
steps {
bunchOfSteps(0)
}
}
}
}
def bunchOfSteps(level) {
if (level < 500) {
withNewSpan(label: 'custom-build-span-' + level, attributes: ([
spanAttribute(key: 'level', value: level),
]), setAttributesOnlyOnParent: true) {
sh "echo level ${level}"
bunchOfSteps(level + 1)
}
}
} |
It would be interesting to compare the RAM usage between pipeline {
agent any
stages {
stage('prepare') {
steps {
bunchOfSteps(0)
}
}
}
}
def bunchOfSteps(level) {
if (level < 500) {
withSpanAttributes([
spanAttribute(key: 'level', value: level),
]) {
sh "echo level ${level}"
bunchOfSteps(level + 1)
}
}
} pipeline {
agent any
stages {
stage('prepare') {
steps {
bunchOfSteps(0)
}
}
}
}
def bunchOfSteps(level) {
if (level < 500) {
withNewSpan(label: 'custom-build-span-' + level, attributes: ([
spanAttribute(key: 'level', value: level),
]), setAttributesOnlyOnParent: true) {
sh "echo level ${level}"
bunchOfSteps(level + 1)
}
}
}
|
this one directly crash after 250 steps, but I not see the memory change after several executions def bunchOfSteps(level) {
if (level < 500) {
withSpanAttributes([
spanAttribute(key: 'level', value: level),
]) {
sh "echo level ${level}"
bunchOfSteps(level + 1)
}
}
} |
I am going to test this one too def bunchOfSteps(level) {
if (level < 500) {
withNewSpan(label: 'custom-build-span-' + level, setAttributesOnlyOnParent: true) {
sh "echo level ${level}"
bunchOfSteps(level + 1)
}
}
} |
I am going to change the approach recursivity 500 it is a lite too much for a pipeline |
pipeline {
agent any
stages {
stage('prepare') {
steps {
bunchOfSteps(0)
}
}
}
}
def bunchOfSteps(level) {
if (level < 10) {
recursiveSteps(0)
bunchOfSteps(level + 1)
}
}
def recursiveSteps(level){
if (level < 50) {
withNewSpan(label: 'custom-build-span-' + level, attributes: ([
spanAttribute(key: 'level', value: level),
]), setAttributesOnlyOnParent: true) {
sh "echo level ${level}"
recursiveSteps(level + 1)
}
}
} |
I am also testing pipeline {
agent any
stages {
stage('prepare') {
steps {
withNewSpan(label: 'custom-build-span', attributes: ([
spanAttribute(key: 'level', value: 'foo'),
]), setAttributesOnlyOnParent: false) {
bunchOfSteps(0)
}
}
}
}
}
def bunchOfSteps(level) {
if (level < 500) {
sh "echo level ${level}"
bunchOfSteps(level + 1)
}
} |
I need to grab some head dumps and verify there is nothing weird. |
opentelemetry-plugin
issue: #90This PR is based on the work done on PR #84.
The patch is adding a new step
withNewSpan
which allows users to create their own spans.The option accepts 3 parameters
label
attributes
withSpanAttributes
setAttributesOnlyOnParent
From the above 3 parameters, only the
label
is required and everything else is optional.Example usage
or
or
withNewSpan
to be consistent with the naming of other steps likewithSpanAttributes
SpanAttributeStepExecution
was reusedTesting done
MonitorPipelineListener
Screenshot from manual testing
Submitter checklist