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

Micrometer Observation component #9389

Merged

Conversation

marcingrzejszczak
Copy link
Contributor

@marcingrzejszczak marcingrzejszczak commented Feb 20, 2023

A list of questions and TODOs related to this component that we must resolve before merging

Discuss:

  • The Tracer abstraction from Camel has a notion of only high cardinality tags, we are missing low cardinality tags for metrics (that means that metrics will not have any tags at this point)
  • Are the changes in the Tracer in the tracing component acceptable?

TODO:

  • Spring Boot Starter is missing
  • Polish the documentation
  • Currently the behaviour is almost identical to OpenTelemetry one, that requires the presence of custom handlers - I'm considering to remove them so that the additional code will not be necessary. That will mean that with Micrometer Observation with OTel Tracer the spans will be a little bit different than with the OpenTelemetry component

Recrated from #9377

@github-actions
Copy link
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟

⚠️ Please note that the changes on this PR may be tested automatically.

If necessary Apache Camel Committers may access logs and test results in the job summaries!

Copy link
Contributor

@orpiske orpiske left a comment

Choose a reason for hiding this comment

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

Just adding a comment about something that caught my eye (but haven't reviewed it fully).

And, also, thanks for your contribution!

@github-actions
Copy link
Contributor

Components tested:

Total Tested Failed ❌ Passed ✅
5 5 4 0

@github-actions
Copy link
Contributor

Components tested:

Total Tested Failed ❌ Passed ✅
6 6 4 2

Copy link
Contributor

@oscerd oscerd left a comment

Choose a reason for hiding this comment

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

This looks good to me with a rapid review.

@oscerd
Copy link
Contributor

oscerd commented Feb 28, 2023

A list of questions and TODOs related to this component that we must resolve before merging

Discuss:

  • The Tracer abstraction from Camel has a notion of only high cardinality tags, we are missing low cardinality tags for metrics (that means that metrics will not have any tags at this point)
  • Are the changes in the Tracer in the tracing component acceptable?

TODO:

  • Spring Boot Starter is missing

This is not a problem, we could do that later

  • Polish the documentation

This could be done with a subsequent PR

  • Currently the behaviour is almost identical to OpenTelemetry one, that requires the presence of custom handlers - I'm considering to remove them so that the additional code will not be necessary. That will mean that with Micrometer Observation with OTel Tracer the spans will be a little bit different than with the OpenTelemetry component

On this, I'm not really sure about it: if we goes this way it's important to document and notes the difference, otherwise users might think the result will be the same with Micrometer and Opentelemetry and it won't be the case

Recrated from #9377

@oscerd
Copy link
Contributor

oscerd commented Feb 28, 2023

Please rebase on 3.x, so we are good. Waiting for @orpiske and @davsclaus reviews.

Copy link
Contributor

@orpiske orpiske left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution!

@davsclaus
Copy link
Contributor

Thanks for the big work, there is a little merge conflict, I wonder if you could resolve that and push update to this PR so it can be merged cleanly.

Also we would need this to be ported to Camel v4 (main) but that is JDK17 and JakartaEE; which I assume micrometer also works with, but just wanted to mention the difference to Camel v3.

Added low cardinality tags, changed the implementation to be as close as possible to the OTel one. Left the handlers as examples of how to make the behaviour equal to the OTel one.
@marcingrzejszczak
Copy link
Contributor Author

marcingrzejszczak commented Mar 1, 2023

I fixed the conflicts and did some additional changes

  • modified the tracer api to introduce a low cardinality tag (those would be used for metrics and traces)
  • modified the current micrometer observation behaviour to remove the custom handlers

Below you have a screenshot of a trace view for a very simple route

@Component
class MyRoute extends RouteBuilder {

	@Override
	public void configure() throws Exception {
		from("direct://foo")
				.log("hello")
				.to("http://httpbin.org/headers");
	}

}

image

With the Micrometer Observation you also get the following metric.

MeterId{name='camel.operation', tags=[tag(HTTP_METHOD=GET),tag(HTTP_STATUS=200),tag(component=camel-http),tag(error=none)]}

I also changed the behaviour so that it is close to the OpenTelemetry one but not the same - I will document the differences plus I've left the code in the tests that can be used to have the same behaviour.

So the question to you is - do you find such information valuable (traces and metrics) in its current form if you were to troubleshoot any issues within a Camel based system? I can try a more complex scenario and we can discuss what metrics / tags can be more useful in your opinion. We can also play around with the names if you think e.g. name of the component should be there in a span name.

As for Jakarta - Micrometer is working fine with JDK17.

cc @bclozel @jonatan-ivanov @shakuzen

@marcingrzejszczak
Copy link
Contributor Author

marcingrzejszczak commented Mar 2, 2023

So I've been playing around with this and I'm really surprised with how it's actually working currently with OpenTelemetry. Let's assume that I have the following routes

from("direct://foo")
				.log("hello")
				.to("direct://bar")
				.to("http://example.org");
		from("direct://bar")
				.log("hello")
				.to("direct://micrometer")
				.to("http://example.org");
		from("direct://micrometer")
				.setHeader(MicrometerConstants.HEADER_METRIC_NAME, constant("new.name"))
				.setHeader(MicrometerConstants.HEADER_METRIC_TAGS, constant(Tags.of("dynamic-key", "dynamic-value")))
				.to("micrometer:counter:name.not.used?tags=key=value")
				.to("direct://baz");
		from("direct://baz")
				.log("hello")
				.to("bean:com.example.cameldemo.MyBean")
				.to("exec:wc?args=--words /usr/share/dict/words")
				.process(exchange -> {
					// Use the Camel Exec String type converter to convert the ExecResult to String
					// In this case, the stdout is considered as output
					String wordCountOutput = exchange.getIn().getBody(String.class);
					// do something with the word count
					System.out.println(wordCountOutput);
				})
				.to("file:///tmp/camel-outputdir?flatten=true")
				.to("http://example.org");

I would assume that for the whole flow (e.g. from producerTemplate.send("direct://foo", defaultExchange);) to the end I would have a single trace. From what I see this is not the case cause all direct:// components are completely ignored in terms of continuing a trace (look at TracingEventNotifier:shouldExclude method).

image

image

Is this really the intent of how this should actually work? I would assume that there should be 1 trace for the whole processing because otherwise this doesn't make a lot of sense (at least to me).

@oscerd
Copy link
Contributor

oscerd commented Mar 2, 2023

As far as I remember it was not really easy to have a full trace, in the end we were able to have one trace for each route.

This means from..to, when you pass to another from..to, like for example

	from("direct://bar")
			.log("hello")
			.to("direct://micrometer")

This will be another trace. I don't remember the reason, but I think instrumenting it to take into account all the routes for a single trace was too hard to implement or too invasive. I might remember wrongly nevertheless

@marcingrzejszczak
Copy link
Contributor Author

This will be another trace. I don't remember the reason, but I think instrumenting it to take into account all the routes for a single trace was too hard to implement or too invasive. I might remember wrongly nevertheless

This will actually not be a trace because direct seems to be an internal component that gets ignored.

@oscerd
Copy link
Contributor

oscerd commented Mar 2, 2023

This will be another trace. I don't remember the reason, but I think instrumenting it to take into account all the routes for a single trace was too hard to implement or too invasive. I might remember wrongly nevertheless

This will actually not be a trace because direct seems to be an internal component that gets ignored.

This looks wrong then. Can you open an issue?

@oscerd
Copy link
Contributor

oscerd commented Mar 2, 2023

Thanks

@github-actions
Copy link
Contributor

github-actions bot commented Mar 2, 2023

Components tested:

Total Tested Failed ❌ Passed ✅
5 5 4 0

@marcingrzejszczak
Copy link
Contributor Author

marcingrzejszczak commented Mar 3, 2023

IMO the graph should like this (please correct me if I'm wrong). Actually it's still missing calls to example.org, file or exec

from("direct://foo")
				.log("hello")
				.to("direct://bar")
				.to("http://example.org");
		from("direct://bar")
				.log("hello")
				.to("direct://micrometer")
				.to("http://example.org");
		from("direct://micrometer")
				.setHeader(MicrometerConstants.HEADER_METRIC_NAME, constant("new.name"))
				.setHeader(MicrometerConstants.HEADER_METRIC_TAGS, constant(Tags.of("dynamic-key", "dynamic-value")))
				.to("micrometer:counter:name.not.used?tags=key=value")
				.to("direct://baz");
		from("direct://baz")
				.log("hello")
				.to("bean:com.example.cameldemo.MyBean")
				.to("exec:wc?args=--words /usr/share/dict/words")
				.process(exchange -> {
					// Use the Camel Exec String type converter to convert the ExecResult to String
					// In this case, the stdout is considered as output
					String wordCountOutput = exchange.getIn().getBody(String.class);
					// do something with the word count
					System.out.println(wordCountOutput);
				})
				.to("file:///tmp/camel-outputdir?flatten=true")
				.to("http://example.org");

image

We have a red graph beacuse I'm explicitly throwing an exception in a controller in my application.

I've achieved this graph by removing the instanceof check here (https://github.com/apache/camel/blob/camel-3.x/components/camel-tracing/src/main/java/org/apache/camel/tracing/Tracer.java#L296) but obviously I might be missing sth. I'm not committing that change, but if you confirm my assumptions I can file an issue and point to a potential solution.

EDIT: I'm still wondering why I don't see a span for the external call to example.org, to file component nor to exec... I would need to investigate that

@marcingrzejszczak
Copy link
Contributor Author

image

Actually everything is fine after doing the before mentioned change. I didn't have the file or exec only because I was throwing an exception in the bean component and the exchange processing was stopped 🤦

So how do we proceed? I mean should I commit the change with the exclusion or not?

@davsclaus
Copy link
Contributor

The latest observation screenshot looks really great, with all the span details.

@marcingrzejszczak are you referring to the shouldExclude method you linked above, where you can only make this work if you remove that entirely or what?

@marcingrzejszczak
Copy link
Contributor Author

@marcingrzejszczak are you referring to the shouldExclude method you linked above, where you can only make this work if you remove that entirely or what?

Yes, I'm referring to that. So I made it work by changing the method from this

 private boolean shouldExclude(SpanDecorator sd, Exchange exchange, Endpoint endpoint) {
            return sd instanceof AbstractInternalSpanDecorator || !sd.newSpan()
                    || isExcluded(exchange, endpoint);
        }

to this

 private boolean shouldExclude(SpanDecorator sd, Exchange exchange, Endpoint endpoint) {
            return !sd.newSpan()
                    || isExcluded(exchange, endpoint);
        }

@davsclaus
Copy link
Contributor

Ah okay, so AbstractInternalSpanDecorator is intended for camel components that are used for internal communication like direct / seda etc. And in your example above you call routes from routes via direct:bar/direct:baz. Do you not see spans for those or how does it filter those?

@marcingrzejszczak
Copy link
Contributor Author

So without my change afair you'll see spans but not for direct components and you'll not see a single trace for the whole flow of a message but you'll see multiple different traces. That's because spans are no longer maintaining parent child relationship.

@davsclaus
Copy link
Contributor

Okay I think we can accept that code change. Are all the unit test passing with this PR in both camel-tracing and camel-micrometer ?

@marcingrzejszczak
Copy link
Contributor Author

Okay I think we can accept that code change. Are all the unit test passing with this PR in both camel-tracing and camel-micrometer ?

If I do the change to the shouldExclude a lot of tests in camel-opentelemetry are failing because number of spans is invalid (previously they were ignored, now they are not).

@oscerd
Copy link
Contributor

oscerd commented Mar 7, 2023

Maybe we could mark them as disabled and get back to them once we have the fix in place.

@marcingrzejszczak
Copy link
Contributor Author

marcingrzejszczak commented Mar 7, 2023

It's up to you - I don't have a problem with adding back the code from the shouldExclude method so that we merge this with all the tests passing and then filing a new issue that most likely shouldExclude method is broken and then we could fix micrometer, opentracing and opentelemetry module tests. WDYT? I'll do whatever you suggest :)

@oscerd
Copy link
Contributor

oscerd commented Mar 7, 2023

If you time to do that, it would be nice, we are probably in the same situation on main, 3.x and 3.20.x, so we should fix the shouldExclude method on LTS branch too (3.20.x). To me it's +1. Thanks a lot for your time.

@marcingrzejszczak
Copy link
Contributor Author

OK so I'm changing this PR as ready for review

@marcingrzejszczak marcingrzejszczak marked this pull request as ready for review March 7, 2023 15:20
@marcingrzejszczak
Copy link
Contributor Author

Hopefully I fixed checkstyle issues and also I've created the new issue here https://issues.apache.org/jira/browse/CAMEL-19124

@marcingrzejszczak
Copy link
Contributor Author

I have no idea why https://github.com/apache/camel/actions/runs/4314828399/jobs/7528671102 is failing - I ran the build locally and it's fine

➜  camel git:(micrometer-observation) ✗ ./mvnw clean install -pl :camel-tracing,:camel-observation,:camel-opentracing,:camel-opentelemetry --also-make
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for Camel 3.21.0-SNAPSHOT:
[INFO] 
[INFO] Camel .............................................. SUCCESS [  0.652 s]
[INFO] Camel :: Parent .................................... SUCCESS [  0.051 s]
[INFO] Camel :: Init ...................................... SUCCESS [  0.015 s]
[INFO] Camel :: Maven Plugins :: Enhanced Bundle Plugin ... SUCCESS [  2.018 s]
[INFO] Camel :: Tooling ................................... SUCCESS [  0.053 s]
[INFO] Camel :: Tooling :: Util ........................... SUCCESS [  2.282 s]
[INFO] Camel :: Tooling Parent ............................ SUCCESS [  0.016 s]
[INFO] Camel :: Maven Plugins ............................. SUCCESS [  0.015 s]
[INFO] Camel :: SPI Annotations ........................... SUCCESS [  0.535 s]
[INFO] Camel :: Util :: JSon .............................. SUCCESS [  1.471 s]
[INFO] Camel :: Tooling :: Model .......................... SUCCESS [  1.648 s]
[INFO] Camel :: Maven Plugins :: Camel Maven Package ...... SUCCESS [  4.789 s]
[INFO] Camel :: Core Modules .............................. SUCCESS [  0.149 s]
[INFO] Camel :: Util ...................................... SUCCESS [ 10.665 s]
[INFO] Camel :: API ....................................... SUCCESS [  5.360 s]
[INFO] Camel :: Management API ............................ SUCCESS [  1.957 s]
[INFO] Camel :: Support ................................... SUCCESS [ 40.214 s]
[INFO] Camel :: Base ...................................... SUCCESS [  3.094 s]
[INFO] Camel :: Base Engine ............................... SUCCESS [  5.228 s]
[INFO] Camel :: Core Processor ............................ SUCCESS [  6.103 s]
[INFO] Camel :: Core Model ................................ SUCCESS [  9.876 s]
[INFO] Camel :: Core Reifier .............................. SUCCESS [  4.901 s]
[INFO] Camel :: Core Engine ............................... SUCCESS [  3.653 s]
[INFO] Camel :: Core Languages ............................ SUCCESS [  3.329 s]
[INFO] Camel :: Components ................................ SUCCESS [  0.169 s]
[INFO] Camel :: Bean ...................................... SUCCESS [  4.853 s]
[INFO] Camel :: Browse .................................... SUCCESS [  1.343 s]
[INFO] Camel :: Cluster ................................... SUCCESS [  1.717 s]
[INFO] Camel :: Controlbus ................................ SUCCESS [  1.534 s]
[INFO] Camel :: Dataformat ................................ SUCCESS [  1.521 s]
[INFO] Camel :: Mock ...................................... SUCCESS [  2.393 s]
[INFO] Camel :: DataSet ................................... SUCCESS [  1.895 s]
[INFO] Camel :: Direct .................................... SUCCESS [  1.483 s]
[INFO] Camel :: Direct VM ................................. SUCCESS [  1.660 s]
[INFO] Camel :: File ...................................... SUCCESS [  4.087 s]
[INFO] Camel :: Health .................................... SUCCESS [  1.835 s]
[INFO] Camel :: Language .................................. SUCCESS [  1.407 s]
[INFO] Camel :: Log ....................................... SUCCESS [  1.607 s]
[INFO] Camel :: Ref ....................................... SUCCESS [  1.264 s]
[INFO] Camel :: REST ...................................... SUCCESS [  2.161 s]
[INFO] Camel :: Saga ...................................... SUCCESS [  1.446 s]
[INFO] Camel :: Scheduler ................................. SUCCESS [  1.397 s]
[INFO] Camel :: Seda ...................................... SUCCESS [  1.824 s]
[INFO] Camel :: VM ........................................ SUCCESS [  1.259 s]
[INFO] Camel :: Stub ...................................... SUCCESS [  1.313 s]
[INFO] Camel :: Timer ..................................... SUCCESS [  1.455 s]
[INFO] Camel :: XML IO Util ............................... SUCCESS [  1.177 s]
[INFO] Camel :: XML JAXP .................................. SUCCESS [  3.574 s]
[INFO] Camel :: Validator ................................. SUCCESS [  1.465 s]
[INFO] Camel :: XPath ..................................... SUCCESS [  1.701 s]
[INFO] Camel :: XSLT ...................................... SUCCESS [  1.974 s]
[INFO] Camel :: XML JAXB .................................. SUCCESS [  1.638 s]
[INFO] Camel :: Core Catalog .............................. SUCCESS [  1.830 s]
[INFO] Camel :: Core ...................................... SUCCESS [03:47 min]
[INFO] Camel :: Management ................................ SUCCESS [ 41.095 s]
[INFO] Camel :: Test :: Parent ............................ SUCCESS [  0.019 s]
[INFO] Camel :: Test :: JUnit5 ............................ SUCCESS [ 13.717 s]
[INFO] Camel :: Cron ...................................... SUCCESS [  2.651 s]
[INFO] Camel :: Spring .................................... SUCCESS [  2.466 s]
[INFO] Camel :: Core XML .................................. SUCCESS [  4.431 s]
[INFO] Camel :: Cloud ..................................... SUCCESS [  4.785 s]
[INFO] Camel :: Maven Plugins :: Camel EIP Documentation Enricher Plugin SUCCESS [  2.700 s]
[INFO] Camel :: Spring XML ................................ SUCCESS [02:22 min]
[INFO] Camel :: Test :: Spring :: JUnit5 .................. SUCCESS [ 23.632 s]
[INFO] Camel :: HTTP :: Base .............................. SUCCESS [  2.654 s]
[INFO] Camel :: Attachments ............................... SUCCESS [  3.285 s]
[INFO] Camel :: HTTP :: Common ............................ SUCCESS [  4.434 s]
[INFO] Camel :: Jackson ................................... SUCCESS [  8.253 s]
[INFO] Camel :: JAXB ...................................... SUCCESS [ 20.077 s]
[INFO] Camel :: Swagger Java (deprecated) ................. SUCCESS [  6.204 s]
[INFO] Camel :: Jetty :: Common ........................... SUCCESS [  2.490 s]
[INFO] Camel :: Test Infra ................................ SUCCESS [  0.011 s]
[INFO] Camel :: Test Infra :: Parent ...................... SUCCESS [  0.014 s]
[INFO] Camel :: Test Infra :: Common ...................... SUCCESS [  0.884 s]
[INFO] Camel :: Test Infra :: Jetty ....................... SUCCESS [  0.856 s]
[INFO] Camel :: HTTP ...................................... SUCCESS [ 28.500 s]
[INFO] Camel :: Jetty ..................................... SUCCESS [01:43 min]
[INFO] Camel :: Common Tracing ............................ SUCCESS [  4.115 s]
[INFO] Camel :: Micrometer Observation .................... SUCCESS [ 51.603 s]
[INFO] Camel :: OpenTracing (deprecated) .................. SUCCESS [01:17 min]
[INFO] Camel :: OpenTelemetry ............................. SUCCESS [ 51.429 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  16:33 min
[INFO] Finished at: 2023-03-07T17:09:07+01:00
[INFO] ------------------------------------------------------------------------
[WARNING] The requested profile "spring" could not be activated because it does not exist.

@davsclaus
Copy link
Contributor

Yeah. the github action fails for some of these checkstyle on 3.x but its a false error.

Thanks for the hard work on this.
We need to port this to main branch as well for Camel v4.

@davsclaus
Copy link
Contributor

Can you work on the SB starter for the 3.x branch, so we have all together. Then afterwards we can possible cherry pick to main branch. If not then we appreciate if you would then work on PRs for main so we have this in v4 as well.

@davsclaus
Copy link
Contributor

merging this for 3.x so its included in Camel 3.21 onwards.

@davsclaus davsclaus merged commit bb9e1d7 into apache:camel-3.x Mar 8, 2023
2 of 4 checks passed
@davsclaus
Copy link
Contributor

Also I wonder if you would contribute an example such as for camel-spring-boot-examples. And you are welcome to include screenshots in the example as it helps users to quickly see this awesome feature

@davsclaus
Copy link
Contributor

Screenshots is also welcome in docs. However they may be harder to do, and the img may need to go in docs root folder where we have images for other pages such as EIPs

@marcingrzejszczak
Copy link
Contributor Author

marcingrzejszczak commented Mar 8, 2023

Sure I can work on the starter. Of course the screenshots should be done after we fix the issue with shouldExclude method because the trace view will be broken. Also, I can work on the examples.

@marcingrzejszczak marcingrzejszczak deleted the micrometer-observation branch March 9, 2023 12:59
@marcingrzejszczak
Copy link
Contributor Author

Spring Boot configuration apache/camel-spring-boot#784
Spring Boot example apache/camel-spring-boot-examples#98

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants