-
Notifications
You must be signed in to change notification settings - Fork 206
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
Feature/add custom #118
Feature/add custom #118
Conversation
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.
Hey @skynet2. Thank you very much for the PR!
the problem with adding Custom
is that there is an ongoing discussion that it’ll be maybe deprecated: elastic/apm#7. (No final decision atm)
The plan is to use Tags
instead. I know, there are some differences, since you can’t just put anything into tags, but on the other hand putting non-serialisable things into the context would cause troubles anyway. So I’d like to be on the safe side and not add something that we may need to remove from the public API soon.
Regarding your problem and the initialisation of Request
and Response
: We can definitely discuss this. The strategy was to only make things public in the preview release that are 100% remain public in the future - in order to avoid breaking changes.
But as we move forward, we’d like to extend the API and make more things public.
I think your approach with introducing an IRequest
interface and make that public on ITransaction
and then just returning the _context.Value?.Request
in Transaction
is a nice solution. I'd like to hide the Context
itself, which is the case here, so that's fine. We can extend this to cover Response
and add additional fields to the public interface. If you elaborate on your scenario, and you tell me which fields you need to set (I suspect it's things like StatusCode
) we can discuss it.
So, in sum: we should revert the Custom
part, sorry about that, but to avoid troubles later I think that’s the best option for now.
The IRequest
part is fine, we can merge that. Usually we cover things with tests, if you are interested in writing those, just take a look at the tests/Elastic.Apm.Tests
project and make sure that we cover the new fields and new interface in at least one test. Otherwise I’ll do it myself ;).
Hi @gregkalapos , Basically, for the request, there is another way, as I added Request.RequestBody property which doesn`t have a limit on the length, but for the response, there is no such property. About IRequest
|
I see, thanks for the clarification. Yes, I see the problem - and Btw. what exactly do you want to store in the To
|
Hello @gregkalapos , Going to refactor Request\Response to Lazy. In order to extract IReqest i will need to create also IUrl and ISocket... and make them also lazy. Maybe we can expose them as public, or you want to have them exactly as interface? |
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.
Thank you for pushing the changes @skynet2!
Especially thanks for implemented trimming of strings, thats a very useful improvement... it was on our TODO list. 👍
Regarding custom: thanks for removing it, now I understand your use-case and I'll try to make sure we have something that covers your use-case. As you can see we have some contrary issues... let's see what the decision is and we'll implement something accordingly in the .NET agent.
Regarding IRequest
and having only 1 implementation: what you say is totally right, nevertheless I'd still introduce interfaces. This would be the public API and the schema to the APM Server can change... we have changes all the time. Having only 1 class would make it very hard to move things forward and deprecate things if it's needed. We have this challenge with basically every class under Model/Payload
. To give you an example: we consider renaming Tags
to Labels
, because we want to confirm to the elastic common schema. By having an interface we can keep Tags
and add a new Labels
field and mark Tags
deprecated but and simply redirect the values to Labels
. And long term in let's say 2-3 versions later we can remove the field. This is way better for existing users than to break something immediately. (Side note: as long as the .NET agent is not GA, we are ok with breaking things, but after GA this will change). Tags
is just an example, and this can happen all the time. Usually I'm not a big fan of interfaces with 1 implementation, but the public API is something where we definitely have to be on the safe side and interfaces give us more flexibility. Hope this makes sense.
So to your comment:
In order to extract IReqest i will need to create also IUrl and ISocket... and make them also lazy. Maybe we can expose them as public, or you want to have them exactly as interface?
If we want to make them public I'd add interfaces to them and expose them through those interfaces.
Btw. the current change set is fine to merge, so if you don't need Url
or Socket
I'm ok with having those only as internal classes. In case you need those feel free to add an interface and expose them that way.
Not very familar with commit workflow for GitHub, we are using bitbucket in the company.
When you request changes, i do that changes, should i click on "resolve issue" or it should be clicked by you?
If you feel we agree on it and it's implemented feel free to push "resolve" - I personally also add a last comment with "done" or something similar as you did... with that other people can easily spot that it reached an agreement and it was implemented.
Lastly one small thing: we should have tests that cover 'User' and 'Body'. Before I merge I'll add tests for that.
Thank you for your help! I really appreciate it! 🚀
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.
@skynet2 tests in the Elastic.Apm.AspNetCore.Tests
are failing because the lazy initialisations in Context.cs
don't work. I added a comment on how to fix it.
Btw. we have standard XUnit tests... you can start those directly from Rider.
Hi @gregkalapos , Thanks, my fail, fixed. Thanks, |
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.
Great, thank you very much @skynet2!!
Codecov Report
@@ Coverage Diff @@
## master #118 +/- ##
=========================================
+ Coverage 84.09% 85.39% +1.3%
=========================================
Files 35 37 +2
Lines 1012 1123 +111
Branches 130 147 +17
=========================================
+ Hits 851 959 +108
- Misses 115 116 +1
- Partials 46 48 +2
Continue to review full report at Codecov.
|
Hi @gregkalapos , please don`t merge yet, looks like there are some cases which are not covered by tests. Currently, i`m getting that issue |
Och, good catch, I see! The problem with
Then we initialized Hmm... this is an interesting problem. 🤔 |
I see two ways how we can solve that :
What do you think @gregkalapos |
The second way will not work, as it`s auto property. |
Yes, and the problem with the 2. approach is that it can be partially initialized. E.g. in The "not so nice" thing about the 1. approach is that if those are properties, then if someone does not initialize it then there could be nullref exceptions. I'm thinking about this... I'll try to come up with something soon :) Also feel free to let me know if you have something in mind. |
What about utilizing ValueTuples? Instead of having an
This way the user code either sets everything we need for a The disadvantage here is that we require also non-required fields and that can be too much sometimes. With this solution, in the implementation (like the |
Hi @gregkalapos , I think it`s easier to expose class with a constructor which requires a list of a parameter (for example url can be one of that parameters) . For example, in order to initialize Request, you should pass Url into a constructor |
This property would not be serialized, this is just the interface that users use. We serialize the values on the |
My problem with having a constructor is that we'll use those classes as properties and it'd mean that can easily end up with For example:
And then in the user code someone writes this:
In this case |
As i understand, in some cases such properties such as Request and Response can be null. Maybe we should use Builder pattern ? |
As i can see in golang apm they use pretty the same principle https://github.com/elastic/apm-agent-go/blob/master/context.go |
@skynet2 In the Go code there is only 1 method specifically for the Regarding the builder pattern: We can discuss that, but I don't see how you force the user on the API level that they pass all required fields. It could be that there is only 1 method and that expects all required properties, but then why do we need the builder pattern? It could be a simple property, and if it's not used we don't send the Since this discussion is already drifted from the PR, could we solve this problem here? #124 (it's work in progress, I'll add some potential solutions soon). Once we have a decision there we can continue with the PR here. |
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-hold until we solve the API problem here: #124
@gregkalapos mind explaining this a bit more concretely? This could also be done with a single If the server renames a property that is a breaking change that should only happen on a major version. |
True, this can be also done with a single |
Add Custom fields. Add the possibility to specify request_body
=============
p.s i need some help from you guys. There is a possible problem that Request and Response will be null on Context object when you create transaction manually.
For now, i can see initialization for Request and Response only in internals libs such as Elastic.Apm.AspNetCore. The issue is that we need to have some mechanism of initialization for that objects outside of internal namespaces, for example for some custom rpc handlers or protocols. Any suggestions around that? We can pass some parameter to StartTransactionInternal, or pass some initial context object with request\response object or make that fields Lazy or smth like that.
Thanks,
Stas