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

Instrument AWSClient WIP #348

Closed
wants to merge 13 commits into from
Closed

Conversation

pokryfka
Copy link

Early PoC of AWS Client tracing instrumentation.

Package.swift Show resolved Hide resolved
@codecov
Copy link

codecov bot commented Aug 27, 2020

Codecov Report

Merging #348 into main will increase coverage by 0.25%.
The diff coverage is 89.56%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #348      +/-   ##
==========================================
+ Coverage   74.09%   74.34%   +0.25%     
==========================================
  Files          60       61       +1     
  Lines        4439     4545     +106     
==========================================
+ Hits         3289     3379      +90     
- Misses       1150     1166      +16     
Impacted Files Coverage Δ
Sources/AWSSDKSwiftCore/AWSService.swift 0.00% <0.00%> (ø)
...WSSDKSwiftCore/Credential/CredentialProvider.swift 89.58% <ø> (-8.34%) ⬇️
Sources/AWSSDKSwiftCore/HTTP/AWSHTTPClient.swift 71.42% <0.00%> (ø)
...Credential/RuntimeSelectorCredentialProvider.swift 90.00% <75.00%> (ø)
Sources/AWSTestUtils/TestTracer.swift 83.67% <83.67%> (ø)
Sources/AWSSDKSwiftCore/AWSClient.swift 88.55% <91.25%> (+0.90%) ⬆️
Sources/AWSSDKSwiftCore/AWSClient+Paginate.swift 100.00% <100.00%> (ø)
...Core/Credential/ConfigFileCredentialProvider.swift 100.00% <100.00%> (ø)
...ftCore/Credential/DeferredCredentialProvider.swift 100.00% <100.00%> (ø)
...ftCore/Credential/MetaDataCredentialProvider.swift 94.73% <100.00%> (-1.06%) ⬇️
... and 8 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 889f95c...a35c193. Read the comment docs.

@pokryfka pokryfka marked this pull request as draft August 27, 2020 11:43
@pokryfka
Copy link
Author

CC @ktoso @slashmo

Package.swift Show resolved Hide resolved
Sources/AWSSDKSwiftCore/AWSClient.swift Outdated Show resolved Hide resolved
Sources/AWSSDKSwiftCore/AWSClient.swift Outdated Show resolved Hide resolved
Sources/AWSSDKSwiftCore/AWSClient.swift Outdated Show resolved Hide resolved
Sources/AWSSDKSwiftCore/AWSClient.swift Outdated Show resolved Hide resolved
Sources/AWSSDKSwiftCore/AWSClient.swift Show resolved Hide resolved
fileprivate func invoke(_ httpRequest: AWSHTTPRequest, with serviceConfig: AWSServiceConfig, on eventLoop: EventLoop, logger: Logger, context: Context) -> EventLoopFuture<AWSHTTPResponse> {
// TODO: what should be the operation name?
let operationName: String = httpRequest.url.path
var span = InstrumentationSystem.tracingInstrument.startSpan(named: operationName, context: context, ofKind: .client, at: .now())
Copy link
Member

@adam-fowler adam-fowler Aug 27, 2020

Choose a reason for hiding this comment

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

There was a long conversation for the Logger PR in async-http-client swift-server/async-http-client#227 about messages and how they should not include context information but instead the metadata should hold the context. @ktoso was heavily involved in this. I am assuming this should be the case here as well. I've already mentioned elsewhere about adding context keys to the baggage. So the operation name should be something consistent like "invoke".

Copy link
Author

@pokryfka pokryfka Aug 27, 2020

Choose a reason for hiding this comment

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

the metadata should hold the context.

the baggage contains the metadata with the context

my understanding is that the current approach is that we should update baggage and use it to set logger metadata,
see also discussion here swift-server/swift-aws-lambda-runtime#162 (comment)

that way it should not be needed to explicitly change the logger (although as of now LoggingBaggageContextCarrier requires logger to be mutable ...),
also we would also have baggage and logger synced

may be affected by slashmo/gsoc-swift-baggage-context#23 (comment)

same as https://github.com/swift-server/async-http-client/pull/289/files#r478461213

Copy link
Member

Choose a reason for hiding this comment

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

You aren't adding any metadata to the baggage though.

I also added this slashmo/gsoc-swift-baggage-context#28. There is no guarantee the baggage is being added to the Logger metadata. You have to trust the implementation of the context object

Copy link
Author

Choose a reason for hiding this comment

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

You aren't adding any metadata to the baggage though.

logger.attachingRequestId(Self.globalRequestID.add(1), operation: operationName, service: serviceConfig.service)

you are right as far as requestId, operationName and service are concerned

the trace context is added, what exactly is added depends on implementation
typically that will include traceId but not requestId (which, as far as XRay is concerned, is span/segment attribute)

@ktoso @slashmo WDYT

this is the same as https://github.com/swift-server/async-http-client/pull/289/files#r478461213

Copy link
Author

@pokryfka pokryfka Aug 27, 2020

Choose a reason for hiding this comment

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

how about sth like:

    private struct RequestMetadata: CustomStringConvertible {
        var requestId: Int
        var service: String
        var operation: String

        var description: String {
            "aws-request-id=\(requestId) aws-service=\(service) aws-operation=\(operation)"
        }
    }
    
    private enum RequestKey: BaggageContextKey {
        typealias Value = RequestMetadata
        var name: String { "AWSRequest" }
    }

then updating the baggage like:

context.baggage[RequestKey.self] = RequestMetadata(requestId: Self.globalRequestID.add(1),
    service: serviceConfig.service,
    operation: "signURL")

instead of updating the logger directly (current):

context.logger = context.logger.attachingRequestId(Self.globalRequestID.add(1), operation: "signURL", service: serviceConfig.service)

Copy link
Member

Choose a reason for hiding this comment

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

What does the Logger output look like?

Copy link
Member

Choose a reason for hiding this comment

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

Ignore that saw your comment above

Copy link
Member

Choose a reason for hiding this comment

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

When it comes to logger formatting I leave that to @ktoso he has stronger views on this I think :-)

Copy link

Choose a reason for hiding this comment

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

It could be just that NoOpTracingInstrument and it's span are wrong, I'll have to consult OTel but it seems reasonable that we should always carry and the Noop is simply implemented wrong/lazy. I did not have much time to work on this in the last week, let's hope next weeks will change that.

Copy link
Author

Choose a reason for hiding this comment

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

Tests/AWSSDKSwiftCoreTests/TracingTests.swift Outdated Show resolved Hide resolved
Sources/AWSSDKSwiftCore/AWSClient.swift Outdated Show resolved Hide resolved
@ktoso
Copy link

ktoso commented Aug 28, 2020

@ktoso is the plan to keep these two packages separate?

You mean baggage and tracing?

Yes, they have to remain separate to avoid weird cyclic dependency issues. Some libs will not want to directly adopt swift-tracing but they will carry baggage context, but nothing more (i.e. not start spans etc)

@pokryfka
Copy link
Author

pokryfka commented Aug 28, 2020

Comments in code.

output of AWSXRaySDKExampleAWS

note that the segments are started when future is created, which does not look nice, hmm

            // TODO: segments are started when future is created
            let listBucketObjects = buckets.map { listObjects(bucket: $0, context: segmentContext) }
            return EventLoopFuture.andAllComplete(listBucketObjects, on: eventLoop)

Screen Shot 2020-08-28 at 14 42 19

some of the attributes recorded by AHC (note that XRay attributes should not have "." so they are removed, this should be mapped to XRay own http object at some point after swift-tracing is released, per pokryfka/aws-xray-sdk-swift#22)

Screen Shot 2020-08-28 at 14 42 50

@pokryfka pokryfka requested a review from adam-fowler August 28, 2020 07:03

// TODO: extensions based on XRaySDK API, temporary, see https://github.com/slashmo/gsoc-swift-tracing/issues/125

private extension TracingInstrument {
Copy link
Member

Choose a reason for hiding this comment

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

Is this temporary until there are changes elsewhere? If not can we move to another file

Copy link
Author

Choose a reason for hiding this comment

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

will do, this code will be redundant if the helpers are created per slashmo/gsoc-swift-tracing#125
I dont think its high priority so this may take a while or maybe will never happen

will move to separate file

Sources/AWSSDKSwiftCore/AWSClient.swift Outdated Show resolved Hide resolved
Sources/AWSSDKSwiftCore/AWSClient.swift Outdated Show resolved Hide resolved
return try awsRequest
.applyMiddlewares(serviceConfig.middlewares + self.middlewares)
.applyMiddlewares(config.middlewares + self.middlewares)
.createHTTPRequest(signer: signer)
Copy link
Member

Choose a reason for hiding this comment

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

The majority of time spent in execute outside of the HTTP request is the signing of the request. This happens inside createHTTPRequest. There currently isn't a span around this.

Copy link
Author

@pokryfka pokryfka Sep 8, 2020

Choose a reason for hiding this comment

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

creating spans for signing and middleware

Sources/AWSSDKSwiftCore/AWSClient.swift Outdated Show resolved Hide resolved
func getCredential(on eventLoop: EventLoop, logger: Logger) -> EventLoopFuture<Credential>
typealias Context = BaggageLogging.LoggingBaggageContextCarrier

func getCredential(on eventLoop: EventLoop, context: CredentialProvider.Context) -> EventLoopFuture<Credential>
Copy link
Member

Choose a reason for hiding this comment

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

I see you have replaced Logger with Context but aren't using it yet in the credential providers code. If you were to start the tracing of the credential providers. I would look at DeferredCredentialProvider.init, RotatingCredentialProvider.refreshCredentials and RuntimeSelectorCredentialProvider.setupInternalProvider. These generally wrap all the other providers.

@adam-fowler
Copy link
Member

I assume you have rebuilt all the aws-sdk-swift service files? Given the trace output you provided. Could you add an aws-sdk-swift PR for them as well?

@pokryfka
Copy link
Author

pokryfka commented Aug 28, 2020

@adam-fowler

I assume you have rebuilt all the aws-sdk-swift service files? Given the trace output you provided. Could you add an aws-sdk-swift PR for them as well?

I have not, no idea how to do it (yet) :-)

I just copied one service and updated them using sed Xcode Find&Replace

its here: https://github.com/pokryfka/aws-xray-sdk-swift/blob/feature/instrument/Examples/Sources/AWSXRaySDKExampleAWS/S3

I dont like that the order of context and eventLoop is different in different places (depending on if eventLoop is optional or not); otherwise I think AWSClient API changes are good to go ...

if services generation is well documented I can try to do it, but I am done with coding this week so this would wait till sometime next week

thank you for the comments, I will get thought them and try to address the issues next week as well

@ktoso
Copy link

ktoso commented Aug 28, 2020

I dont like that the order of context and eventLoop is different in different places (depending on if eventLoop is optional or not); otherwise I think AWSClient API changes are good to go ...

Yeah the sensitivity of that param depending on that is a bit annoying... could you please provide an example of a few methods like that as a ticket on baggage context? Does it show up a lot?

@adam-fowler
Copy link
Member

I dont like that the order of context and eventLoop is different in different places (depending on if eventLoop is optional or not); otherwise I think AWSClient API changes are good to go ...

Where is the inconsistency. I thought EventLoop was optional in all the api calls. Maybe I missed one

@adam-fowler
Copy link
Member

if services generation is well documented I can try to do it, but I am done with coding this week so this would wait till sometime next week

Assuming you are in aws-sdk-swift folder
cd CodeGenerator
Edit stencil templates in Templates folder. You will need to edit api.stencil and paginator.stencil I think. The format is documented here https://stencil.fuller.li/en/latest/builtins.html. It is similar to mustache.
swift run -c release

Have a good weekend

@pokryfka
Copy link
Author

pokryfka commented Sep 8, 2020

@adam-fowler

I was a bit busy last week.
Got through the comments now and tried to address all of them (except for CredentialsProvider, for now);
looking into generating aws-sdk-swift (that's another repo and another PR).

Now, this is not the final version and there are places for improvements and fixes.
However given very unstable swift-tracing API and active development of the AWSClient
I think it would be quite time consuming to keep it synced (note that I pinned swift-tracing to GIT hashes, so its will keep working but will not use the latest API).

I think the main objectives have been:

  • test how swift-tracing API could be used to instrument AWSClient
  • test how logger and baggage could be propagated with BaggageLogging.LoggingBaggageContextCarrier

I think the next steps are:

  1. wait for swift-tracing release.

My guess it will take 3 months (1 month for "cleanups", 1 for SSWG approval, 1 for "unplanned delay"),
@ktoso could probably comment on that

  1. Agree on AWSClient interface in 5.x.x

@adam-fowler I think you need to decide if the proposed approach makes sense and could be adopted.

if you approve the use BaggageLogging.LoggingBaggageContextCarrier but would rather not delay 5.x.x release for another 3 months, perhaps you could define (code for illustration purpose):

public protocol AWSClientContext {
  var logger: Logger { get }
}

extension AWSClient {
    public typealias Context = AWSClientContext
}

which then could be extended to BaggageLogging.LoggingBaggageContextCarrier without breaking API in, say, 5.1.x

extension AWSClient {
    public typealias Context = BaggageLogging.LoggingBaggageContextCarrier
}

just an idea

@pokryfka
Copy link
Author

pokryfka commented Sep 8, 2020

@adam-fowler @ktoso

I dont like that the order of context and eventLoop is different in different places (depending on if eventLoop is optional or not); otherwise I think AWSClient API changes are good to go ...

Yeah the sensitivity of that param depending on that is a bit annoying... could you please provide an example of a few methods like that as a ticket on baggage context? Does it show up a lot?

Where is the inconsistency. I thought EventLoop was optional in all the api calls. Maybe I missed one

most public function do not require eventLoop (its optional):

    public func copyObject(_ input: CopyObjectRequest, context: AWSClient.Context, on eventLoop: EventLoop? = nil) -> EventLoopFuture<CopyObjectOutput>

some do, in which case the order of context and eventLoop arguments changes

    public func multipartDownload(
        _ input: GetObjectRequest,
        partSize: Int = 5 * 1024 * 1024,
        on eventLoop: EventLoop,
       context: AWSClient.Context,
        outputStream: @escaping (ByteBuffer, Int64, EventLoop) -> EventLoopFuture<Void>
    )

@adam-fowler
Copy link
Member

some do, in which case the order of context and eventLoop arguments changes

    public func multipartDownload(
        _ input: GetObjectRequest,
        partSize: Int = 5 * 1024 * 1024,
        on eventLoop: EventLoop,
       context: AWSClient.Context,
        outputStream: @escaping (ByteBuffer, Int64, EventLoop) -> EventLoopFuture<Void>
    )

That should probably be an optional EventLoop as well

@adam-fowler
Copy link
Member

@pokryfka Going to close this in favour of #443. Any thoughts?

@pokryfka
Copy link
Author

pokryfka commented May 29, 2021

Sure, this one is outdated anyway.


I dont expect you will ship it until AHC supports tracing, which has not happened yet

https://github.com/soto-project/soto-core/pull/443/files#r641917520

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

Successfully merging this pull request may close these issues.

3 participants