Skip to content

Support getting CAPTURE_BODY and TRANSACTION_MAX_SPANS options from central config#577

Merged
SergeyKleyman merged 16 commits intoelastic:masterfrom
SergeyKleyman:Central_config_part_2
Nov 19, 2019
Merged

Support getting CAPTURE_BODY and TRANSACTION_MAX_SPANS options from central config#577
SergeyKleyman merged 16 commits intoelastic:masterfrom
SergeyKleyman:Central_config_part_2

Conversation

@SergeyKleyman
Copy link
Copy Markdown
Contributor

@SergeyKleyman SergeyKleyman commented Oct 29, 2019

Closes #534

@SergeyKleyman SergeyKleyman self-assigned this Oct 29, 2019
Copy link
Copy Markdown
Member

@bmorelli25 bmorelli25 left a comment

Choose a reason for hiding this comment

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

Nice!

Copy link
Copy Markdown
Contributor

@gregkalapos gregkalapos left a comment

Choose a reason for hiding this comment

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

I think overall this is fine - sorry that it took so long for me to go through this.

If I may add some suggestions:

  • If possible please add some comments in the code - that really helps others to understand it (I added below some specific places where it'd help). When you write it, it's totally obvious, I know - but 1-2 lines of comments here and there can make a huge difference for the reader.
  • I think we still have lots of unrelated things in this PR - for now it's fine, I'd not change those, but in the future, especially with these bigger PRs, could we please just focus on what the PR title says? That'd make reviewing easier.

namespace Elastic.Apm.AspNetCore.Extensions
{
public static class TransactionExtensions
internal static class TransactionExtensions
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hmm.. this is technically a breaking change. Probably no one uses it, because this should not be public and I 100% agree with that. I already almost made the same change in one of my previous PRs.

Still I think it'd be best to leave it public and once we release 2.0 make it internal - and go through the code base and fix if there are other similar problems (I think there are).

Unfortunately this was a mistake, but I think it'd be better to fix this on a major release bump.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I agree with your assessment:

Probably no one uses it

So is it worth spending any more time on it?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

So is it worth spending any more time on it?

Yes, because it's just about changing internal back to public and we have 1 less breaking change. That can be done very quickly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately it's not as simple as changing internal back to public because the signature of CollectRequestInfo changed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh, yeah I see. As said here, I'd left it as it is. I know, the IConfigurationReader went away, but technically we could still pass that as a parameter.

Anyway, ok, let's make it internal and hope no one uses it. But could we try to avoid these things in the future please?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Definitely.

ParentId = parentId;
Transaction = new TransactionData(transaction.IsSampled, transaction.Type);

if (transaction.IsSampled) Context = transaction.Context;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I see you move capturing the context from QueueError to the Error .ctor. Is that related to the new configs coming from central config? I think it's not and I'd leave out such changes from these PRs.

I think we discussed on slack that transaction's context should be separated from the error's context. So instead of sharing it, we should capture those differently, in case one of those changes.

Probably similar to other agents (or at least Python) we should also capture Error.Context always - also in case the transaction is not sampled.

But I feel none of these are related to this PR, so I'd prefer everything related to this outside of the PR - unless I overlooked something and it's directly related to fetching the setting values from central config.

public static void CollectRequestInfo(this ITransaction transaction, HttpContext httpContext, IConfigurationReader configurationReader,
IApmLogger logger
)
internal static void CollectRequestBody(this Transaction transaction, bool isForError, HttpRequest request, IApmLogger logger)
Copy link
Copy Markdown
Contributor

@gregkalapos gregkalapos Nov 13, 2019

Choose a reason for hiding this comment

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

I think the only thing related to adding CAPTURE_BODY to central config is that the IConfigurationReader is changed to transaction.ConfigSnapshot, right? Would it be possible that we do other changes (like making this method to capture the body both for errors and not errors, restructuring the code, etc.) in separate PRs in the future? It would make reviews easier - the smaller the PR is the easier it is to review.


if (nameInConfig == adaptedServiceName)
_logger?.Warning()?.Log("Service name provided in configuration is {ServiceName}", nameInConfig);
_logger?.Debug()?.Log("Service name provided in configuration is {ServiceName}", nameInConfig);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is no big deal, but this is I think again unrelated to the title of the PR. I usually switch to master, do this change, create a PR with a new branch and merge these separately - with git this really takes no time. That helps keeping these big PRs smaller.

}

protected List<string> ParseCaptureBodyContentTypes(ConfigurationKeyValue kv, string captureBody)
protected List<string> ParseCaptureBodyContentTypes(ConfigurationKeyValue kv)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sooo..what happens here is that since CAPTURE_BODY is now live changeable, we can't take that into consideration when we read CaptureBodyContentTypes, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That is correct.


[Theory]
[MemberData(nameof(OptionsChangedAfterStartTestVariants))]
public async Task Options_changed_after_start(int startCfgVariantIndex, OptionsTestVariant startCfgVariant)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It'd be really nice to add some comments to this one. To be honest, I already started going through this PR before EAH and this was the point where I gave up - some comments would really help here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

}

private static bool IsCaptureRequestBodyEnabled(Transaction transaction, bool isForError) =>
transaction.ConfigSnapshot.CaptureBody.Equals(ConfigConsts.SupportedValues.CaptureBodyAll)
Copy link
Copy Markdown
Contributor

@gregkalapos gregkalapos Nov 13, 2019

Choose a reason for hiding this comment

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

At least to me IConfigurationReaderExtentions with ShouldExtractRequestBodyOnError and ShouldExtractRequestBodyOnTransactions was easier to follow than this method. - no action needed on this, just saying.

public Context Context => _context.Value;

[JsonIgnore]
internal IConfigSnapshot ConfigSnapshot { get; }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

So, if I understand correctly, the plan is that this is the ConfigSnapshot instance that we pass to every other component like Span and also this instance is used by things like TransactionExtensions, right? If I'm right, then this seems to be a fairly important property and I'd comment it. If I'm wrong, then I'd still comment it, because after looking at the code long enough I got the wrong impression.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

{
var contentType = new ContentType(httpContext.Request.ContentType);
// Is request body already captured?
if (transaction.IsContextCreated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why does transaction.IsContextCreated matter here? 🤔 Is it because transaction.Context.Request would create one? If so, is there any case when only the Body is filled? I don't think so... so if we are here, I think we already have a context anyway, or not?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I didn't want to assume too much about the context in which this method is called - the purpose was to avoid creating empty Context. I've added a comment to the code.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ok, sounds good to me.

var exception = kv.Value.GetType().GetTypeInfo().GetDeclaredProperty("exception").GetValue(kv.Value) as Exception;

var transaction = _agent.Tracer.CurrentTransaction;
var transaction = (Transaction)_agent.Tracer.CurrentTransaction;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hmm.. this cast is a little bit unfortunate - with this it MUST be a Transaction, otherwise it will throw an exception - so e.g. we can't just replace to NoOpTransaction later if needed.

I guess the root cause of the challenge here is that we don't dependency inject the configuration anymore, instead it comes through the Transaction. I'm not sure this is good - could we maybe find another way to flow the ConfigSnapshot?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's not like it's the only place where we assume that ITransaction is actually Transaction - for example

)

If/when we need to have other implementations of ITransaction we will revisit it. For example we can introduce TransactionBase and move ConfigSnapshot there.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd consider a pattern matching based on types very different from a hard cast.

But I think we are good here. In #608 I moved this part out from here, so probably we can also get rid of the cast once we merge that.

Context: In #608 I realized that capturing request body here is not a very good thing, because this is a sync method and reading the body synchronously can cause thread starvation. So I'd say let's leave it as is, and in #608 this will evolve.

@gregkalapos gregkalapos self-requested a review November 19, 2019 14:49
Copy link
Copy Markdown
Contributor

@gregkalapos gregkalapos left a comment

Choose a reason for hiding this comment

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

Discussed on slack.

I hoped to move some of the unrelated changes out from here, or at least some reaction to those here.

Overall no blocker on this PR, but if possible please try to keep these smaller in the future, otherwise it's very hard to review.

Reviewing a couple of hundred lines can be done in a couple of minutes, but having a 1000+ lines PR with 31 files changing, with lots of moving parts takes significantly longer. Adding some comments and making it as small as possible helps the reviewer a lot.

@SergeyKleyman SergeyKleyman merged commit 9cc92fa into elastic:master Nov 19, 2019
@SergeyKleyman SergeyKleyman deleted the Central_config_part_2 branch November 19, 2019 15:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for the next batch of central config options (CAPTURE_BODY and TRANSACTION_MAX_SPANS)

3 participants