-
Notifications
You must be signed in to change notification settings - Fork 785
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
End-to-end example applications #936
End-to-end example applications #936
Conversation
I have two general feedback:
|
|
||
namespace WorkerService | ||
{ | ||
public class RabbitMqConsumer : BackgroundService |
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.
It seems we have more code showing how to use RabbitMq
than OpenTelemetry itself.
Wonder if there is something simpler, that helps people to focus on the custom propagation part.
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.
Yes, I had a similar thought. The applications required a fair amount of boilerplate to get RabbitMQ functionality in place. I can spend a bit of time refactoring things a bit to see if I can get the OpenTelemetry part of it all better highlighted.
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.
Agree that it takes some time to actually get to the OTel tracing/propagation part in the jungle of RabbitMq and boiler plate codes..
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.
Tough crowd, eh? Nice work @alanwest! Messaging is one of the more complex/advanced cases, I actually think this does a great job of capturing it as concisely as possible. I'm sure these a bit of room for improvement but maybe we just need another sample doing something more trivial like calling a web service?
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.
Tough crowd, eh?
😄 not at all, I appreciate the input. Working this afternoon to see what I can do to better highlight the OTel pieces. Stay tuned!
maybe we just need another sample doing something more trivial like calling a web service?
You thinking like a call demonstrating HttpClient instrumentation or something?
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.
You thinking like a call demonstrating HttpClient instrumentation or something?
That's what I was thinking. But we do kind of already have one in there:
opentelemetry-dotnet/examples/AspNetCore/Controllers/WeatherForecastController.cs
Lines 24 to 27 in 3f01bdc
// Making an http call here to serve as an example of | |
// how dependency calls will be captured and treated | |
// automatically as child of incoming request. | |
var res = httpClient.GetStringAsync("http://google.com").Result; |
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 made an effort to separate the OpenTelemetry logic from the RabbitMQ 🌴 🐰 jungle 🐇 🌴.
Basically there are two classes now that are pretty succinct and I think put a pretty good focus on the context propagation:
- The WebApi has a
MessageSender
class - The WorkService has a
MessageProcessor
class
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.
You thinking like a call demonstrating HttpClient instrumentation or something?
That's what I was thinking. But we do kind of already have one in there:
I'm definitely a fan of a more turnkey, holistic example that showcases a number of things. How about after we get some consensus on the direction of this sample, we can discuss what else may make sense to take on, and then do it in smaller follow up PRs?
I would hope that |
That's great!
How about a simple child-process approach - the parent creates child process, passing in |
If all we ultimately want to demonstrate is context propagation, then yes I think something simpler like this would be a good way to go. Though, the concept here is provide a more holistic example incorporating OpenTelemetry and a number of dependencies. I've noted that ultimately eShopOnContainers would be a far better place to showcase this kind of thing. Though in the meantime, perhaps doing something small in the repo could be useful? Before simplifying things too much, I'd like to hear some others' input. I think this PR is a good place to take a pause and let people chime in with other ideas. I'm definitely open to evolving things in a way that people think the community will find most useful. |
In OpenTelemetry Python there is a fairly complex demo app FYI. |
If we can leverage https://github.com/dotnet-architecture/eShopOnContainers as the proper example, then we wouldn't have to maintain a complex example in this repo forever. I think it makes sense to have a less complex, yet demonstrating the concepts (especially manual propagation) in this repo, until we go GA and eShopOnContainer owners can be pursued. |
Codecov Report
@@ Coverage Diff @@
## master #936 +/- ##
==========================================
- Coverage 77.01% 75.54% -1.48%
==========================================
Files 221 221
Lines 6166 6208 +42
==========================================
- Hits 4749 4690 -59
- Misses 1417 1518 +101
|
this.connectionFactory = new ConnectionFactory() | ||
{ | ||
HostName = Environment.GetEnvironmentVariable("RABBIT_HOSTNAME") ?? "localhost", | ||
UserName = "guest", |
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.
Should we switch username & password to also use EnvVar if available? Just to be good internet citizens and encourage people to not hardcode their credentials.
UserName = Environment.GetEnvironmentVariable("RABBIT_USERNAME") ?? "guest",`
Password = Environment.GetEnvironmentVariable("RABBIT_PASSWORD") ?? "guest",`
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.
👍 Good point.
{ | ||
try | ||
{ | ||
string activityName = $"{nameof(RabbitMqService)}.{nameof(PublishMessage)}"; |
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.
Spec says operationName should be <destination name> <operation name>
example $"{QueueName} send"
for publish here. I just noticed that yesterday it might be new?
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.
Ah cool, great call out. I'm really glad to see there's guidance here.
{ | ||
services.AddHostedService<RabbitMqConsumer>(); | ||
|
||
// TODO: Determine if this can be done here in a WorkerService. It does not seem to work... doing this in the RabbitMqConsumer for now. |
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.
The TODO
is really interesting! It should be here right? Wonder if we have a bug somewhere?
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.
Yea, I'll circle back in a bit and see what's going on here.
{ | ||
var parentContext = this.textFormat.Extract(ea.BasicProperties, ExtractTraceContextFromBasicProperties); | ||
|
||
string activityName = $"{nameof(RabbitMqConsumer)}.{nameof(ExecuteAsync)}"; |
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.
Same comment here for the activityName/operationName.
var parentContext = this.textFormat.Extract(ea.BasicProperties, ExtractTraceContextFromBasicProperties); | ||
|
||
string activityName = $"{nameof(RabbitMqConsumer)}.{nameof(ExecuteAsync)}"; | ||
using (var activity = activitySource.StartActivity(activityName, ActivityKind.Server, parentContext)) |
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.
@reyang Being an expert on the spec, should the span/activity created when consuming messages use the propagated context as parent or add as a link ("follows-from")? I would really like us to provide spec-correct guidance where possible.
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.
Short answer: I think the spec is not clear on this yet.
Long answer:
"follows-from" is an OpenTracing concept, which hasn't been formalized in the OpenTelemetry specification:
- Formalize the translation of OpenTracing references to span parent and links opentelemetry-specification#562
- Sync and Async children (FOLLOWS_FROM) opentelemetry-specification#65
Most of the existing backends don't have support for links and I bet they already pass the same trace id over messaging system. And it looks like that the W3C TraceContext for MQTT is going to the same thing. I do think this could expose issue for batch processing and retry, using links instead of following the parent context seems to have more flexibility/power.
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, this is great context. For the immediate purposes I think it makes sense to settle on a parent/child relationship since that's the only thing that most backends support at the moment - if, in particular, Zipkin and/or Jaeger introduce support for visualizing links, then I think it could be cool to demonstrate that.
That aside, I am curious how the spec conversations will evolve. My gut says that there will be value in both use cases. That is, a parent/child relationship may make sense some times and links other times. Though that could make configuration and especially auto-instrumentation complex.
@CodeBlanch I've pushed some changes that should address the issues you were encountering. Both apps can be spun up in any order now with out punishing you 👊, or the need for explaining things in the README. I've also expanded the PR description to include a synopsis of the overall conversation. |
@alanwest LGTM! My vote is to merge. We can always change it, remove it, or move it later. We can have other examples too or add more to this one? The TODO in there still worries me, but doesn't need to be resolved on this PR. @reyang is working on improving the whole build pattern anyway. @cijothomas Defer to you to merge or make a call on this. |
Oh yes thank you! I meant to comment on that. I was thinking leaving the todo in for now and investigate the potential bug in a follow up. I'm away from a computer today, but will update in with some more details soon. |
I think we should move forward and merge 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.
LGTM.
OpenTelemetry.sln
Outdated
@@ -186,6 +186,20 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "logs", "logs", "{3862190B-E | |||
docs\logs\logging-correlation.md = docs\logs\logging-correlation.md | |||
EndProjectSection | |||
EndProject | |||
<<<<<<< HEAD |
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.
This looks like some conflict resolve header?
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.
Oh nice catch! Apparently, Visual Studio was like this is fine
.
…ntelemetry-dotnet into alanwest/end-to-end-example
examples/MicroserviceExample/Utils/Messaging/MessageReceiver.cs
Outdated
Show resolved
Hide resolved
.AddActivitySource(nameof(MessageSender)) | ||
.UseZipkinExporter(b => | ||
{ | ||
var zipkinHostName = Environment.GetEnvironmentVariable("ZIPKIN_HOSTNAME") ?? "localhost"; |
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.
On a followup PR, we should simply get zipkinhostname from this.Configuration. And set this in appsettings.json.
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.
This is namely for when running with docker-compose. I can double-check, but the Zipkin hostname is different as seen by the other containers as it is when hitting it at localhost from a browser.
{ | ||
this.messageReceiver = messageReceiver; | ||
|
||
this.tracerProvider = Sdk.CreateTracerProvider((builder) => |
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.
..lets come back to this. If program.cs sets up everything, then Worker can simply retrieve TracerProvider from DI in constructor.
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.
Ok. Yea, I may have been doing something wrong here. I'll follow up and clean this up.
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.
Ok, this is fixed now.
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.
LGTM - Except we need to show activity? null check in the examples.
This PR in part addresses #854 for building out a slightly more sophisticated sample application.
At this point it is uncertain how much further we want to expand on the idea of a more complex suite of example applications hosted in this repository. Ideally, we can benefit from a more full-fledged example like eShopOnContainers which would we wouldn't necessarily be responsible for maintaining. So, in the meantime, this example may just provide a stopgap solution for demonstrating some of the more complex OpenTelemetry concepts. Namely, context propagation, messaging systems, and the combination of both an HTTP service and a non-HTTP service.
A fair amount of good conversation has already taken place on this PR.
Some people feel that demonstrating some messaging system concepts would be nice. Though, this does understandably make the example a fair bit more complicated with the usage of docker and relatively complex boilerplate for the messaging components.
In an effort to reduce the cognitive distraction of the messaging boilerplate and hopefully emphasize the context propagation, I have attempted to separate the OpenTelemetry logic into the
MessageReceiver
andMessageSender
classes.An alternative has been suggested by @reyang to just focus on the context propagation:
Questions