Skip to content

Commit d5afc27

Browse files
authored
feat: add tracing framework (#756)
1 parent 86f53bc commit d5afc27

File tree

21 files changed

+87
-36
lines changed

21 files changed

+87
-36
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"id": "77594af4-5d59-49d4-b96c-9e1d5a9129e7",
3+
"type": "feature",
4+
"description": "Add a new tracing framework for centralized handling of log messages and metric events and providing easy integration points for connecting to downstream tracing systems (e.g., kotlin-logging)",
5+
"issues": [
6+
"awslabs/smithy-kotlin#677"
7+
]
8+
}

aws-runtime/aws-config/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ kotlin {
2424
implementation("aws.smithy.kotlin:logging:$smithyKotlinVersion")
2525
implementation("aws.smithy.kotlin:hashing:$smithyKotlinVersion")
2626
implementation("aws.smithy.kotlin:http:$smithyKotlinVersion")
27+
implementation("aws.smithy.kotlin:tracing-core:$smithyKotlinVersion")
2728
implementation("aws.smithy.kotlin:utils:$smithyKotlinVersion")
2829
implementation("aws.smithy.kotlin:http-client-engine-default:$smithyKotlinVersion")
2930
implementation(project(":aws-runtime:aws-http"))

aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/CachedCredentialsProvider.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ import aws.sdk.kotlin.runtime.config.ExpiringValue
1010
import aws.smithy.kotlin.runtime.auth.awscredentials.Credentials
1111
import aws.smithy.kotlin.runtime.auth.awscredentials.CredentialsProvider
1212
import aws.smithy.kotlin.runtime.io.Closeable
13-
import aws.smithy.kotlin.runtime.logging.Logger
1413
import aws.smithy.kotlin.runtime.time.Clock
14+
import aws.smithy.kotlin.runtime.tracing.trace
15+
import kotlin.coroutines.coroutineContext
1516
import kotlin.time.Duration
1617
import kotlin.time.Duration.Companion.seconds
1718

@@ -54,8 +55,7 @@ public class CachedCredentialsProvider(
5455
private val cachedCredentials = CachedValue<Credentials>(null, bufferTime = refreshBufferWindow, clock)
5556

5657
override suspend fun getCredentials(): Credentials = cachedCredentials.getOrLoad {
57-
val logger = Logger.getLogger<CachedCredentialsProvider>()
58-
logger.trace { "refreshing credentials cache" }
58+
coroutineContext.trace<CachedCredentialsProvider> { "refreshing credentials cache" }
5959
val providerCreds = source.getCredentials()
6060
if (providerCreds.expiration != null) {
6161
val expiration = minOf(providerCreds.expiration!!, (clock.now() + expireCredentialsAfter))

aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/CredentialsProviderChain.kt

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ package aws.sdk.kotlin.runtime.auth.credentials
77

88
import aws.smithy.kotlin.runtime.auth.awscredentials.Credentials
99
import aws.smithy.kotlin.runtime.auth.awscredentials.CredentialsProvider
10+
import aws.smithy.kotlin.runtime.http.operation.getLogger
1011
import aws.smithy.kotlin.runtime.io.Closeable
11-
import aws.smithy.kotlin.runtime.logging.Logger
12+
import aws.smithy.kotlin.runtime.tracing.*
13+
import kotlin.coroutines.coroutineContext
1214

1315
// TODO - support caching the provider that actually resolved credentials such that future calls don't involve going through the full chain
1416

@@ -23,20 +25,21 @@ import aws.smithy.kotlin.runtime.logging.Logger
2325
public open class CredentialsProviderChain(
2426
protected vararg val providers: CredentialsProvider,
2527
) : CredentialsProvider, Closeable {
26-
private val logger = Logger.getLogger<CredentialsProviderChain>()
27-
2828
init {
2929
require(providers.isNotEmpty()) { "at least one provider must be in the chain" }
3030
}
3131

3232
override fun toString(): String =
3333
(listOf(this) + providers).map { it::class.simpleName }.joinToString(" -> ")
3434

35-
override suspend fun getCredentials(): Credentials {
36-
val chainException = lazy { CredentialsProviderException("No credentials could be loaded from the chain: $this") }
35+
override suspend fun getCredentials(): Credentials = coroutineContext.withChildTraceSpan("Credentials chain") {
36+
val logger = coroutineContext.getLogger<CredentialsProviderChain>()
37+
val provider = this@CredentialsProviderChain
38+
val chainException = lazy { CredentialsProviderException("No credentials could be loaded from the chain: $provider") }
3739
for (provider in providers) {
40+
logger.trace { "Attempting to load credentials from $provider" }
3841
try {
39-
return provider.getCredentials()
42+
return@withChildTraceSpan provider.getCredentials()
4043
} catch (ex: Exception) {
4144
logger.debug { "unable to load credentials from $provider: ${ex.message}" }
4245
chainException.value.addSuppressed(ex)

aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/EcsCredentialsProvider.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import aws.smithy.kotlin.runtime.http.request.HttpRequestBuilder
2323
import aws.smithy.kotlin.runtime.http.request.header
2424
import aws.smithy.kotlin.runtime.http.response.HttpResponse
2525
import aws.smithy.kotlin.runtime.io.Closeable
26-
import aws.smithy.kotlin.runtime.logging.Logger
2726
import aws.smithy.kotlin.runtime.retries.StandardRetryStrategy
2827
import aws.smithy.kotlin.runtime.retries.StandardRetryStrategyOptions
2928
import aws.smithy.kotlin.runtime.retries.delay.ExponentialBackoffWithJitter
@@ -37,6 +36,7 @@ import aws.smithy.kotlin.runtime.serde.json.JsonDeserializer
3736
import aws.smithy.kotlin.runtime.time.TimestampFormat
3837
import aws.smithy.kotlin.runtime.util.Platform
3938
import aws.smithy.kotlin.runtime.util.PlatformEnvironProvider
39+
import kotlin.coroutines.coroutineContext
4040

4141
/**
4242
* The elastic container metadata service endpoint that should be called by the [aws.sdk.kotlin.runtime.auth.credentials.EcsCredentialsProvider]
@@ -80,7 +80,7 @@ public class EcsCredentialsProvider internal constructor(
8080
}
8181

8282
override suspend fun getCredentials(): Credentials {
83-
val logger = Logger.getLogger<EcsCredentialsProvider>()
83+
val logger = coroutineContext.getLogger<EcsCredentialsProvider>()
8484
val authToken = AwsSdkSetting.AwsContainerAuthorizationToken.resolve(platformProvider)
8585
val relativeUri = AwsSdkSetting.AwsContainerCredentialsRelativeUri.resolve(platformProvider)
8686
val fullUri = AwsSdkSetting.AwsContainerCredentialsFullUri.resolve(platformProvider)

aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/EnvironmentCredentialsProvider.kt

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,16 @@ package aws.sdk.kotlin.runtime.auth.credentials
88
import aws.sdk.kotlin.runtime.config.AwsSdkSetting
99
import aws.smithy.kotlin.runtime.auth.awscredentials.Credentials
1010
import aws.smithy.kotlin.runtime.auth.awscredentials.CredentialsProvider
11+
import aws.smithy.kotlin.runtime.tracing.trace
1112
import aws.smithy.kotlin.runtime.util.Platform
13+
import kotlin.coroutines.coroutineContext
1214

1315
private const val PROVIDER_NAME = "Environment"
1416

17+
private val ACCESS_KEY_ID = AwsSdkSetting.AwsAccessKeyId.environmentVariable
18+
private val SECRET_ACCESS_KEY = AwsSdkSetting.AwsSecretAccessKey.environmentVariable
19+
private val SESSION_TOKEN = AwsSdkSetting.AwsSessionToken.environmentVariable
20+
1521
/**
1622
* A [CredentialsProvider] which reads from `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`.
1723
*/
@@ -22,10 +28,15 @@ public constructor(private val getEnv: (String) -> String?) : CredentialsProvide
2228
private fun requireEnv(variable: String): String =
2329
getEnv(variable) ?: throw ProviderConfigurationException("Missing value for environment variable `$variable`")
2430

25-
override suspend fun getCredentials(): Credentials = Credentials(
26-
accessKeyId = requireEnv(AwsSdkSetting.AwsAccessKeyId.environmentVariable),
27-
secretAccessKey = requireEnv(AwsSdkSetting.AwsSecretAccessKey.environmentVariable),
28-
sessionToken = getEnv(AwsSdkSetting.AwsSessionToken.environmentVariable),
29-
providerName = PROVIDER_NAME,
30-
)
31+
override suspend fun getCredentials(): Credentials {
32+
coroutineContext.trace<EnvironmentCredentialsProvider> {
33+
"Attempting to load credentials from env vars $ACCESS_KEY_ID/$SECRET_ACCESS_KEY/$SESSION_TOKEN"
34+
}
35+
return Credentials(
36+
accessKeyId = requireEnv(ACCESS_KEY_ID),
37+
secretAccessKey = requireEnv(SECRET_ACCESS_KEY),
38+
sessionToken = getEnv(SESSION_TOKEN),
39+
providerName = PROVIDER_NAME,
40+
)
41+
}
3142
}

aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/ImdsCredentialsProvider.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,17 @@ import aws.smithy.kotlin.runtime.auth.awscredentials.Credentials
1414
import aws.smithy.kotlin.runtime.auth.awscredentials.CredentialsProvider
1515
import aws.smithy.kotlin.runtime.http.HttpStatusCode
1616
import aws.smithy.kotlin.runtime.io.Closeable
17-
import aws.smithy.kotlin.runtime.logging.Logger
1817
import aws.smithy.kotlin.runtime.serde.json.JsonDeserializer
1918
import aws.smithy.kotlin.runtime.time.Clock
2019
import aws.smithy.kotlin.runtime.time.Instant
20+
import aws.smithy.kotlin.runtime.tracing.info
21+
import aws.smithy.kotlin.runtime.tracing.warn
2122
import aws.smithy.kotlin.runtime.util.Platform
2223
import aws.smithy.kotlin.runtime.util.PlatformEnvironProvider
2324
import aws.smithy.kotlin.runtime.util.asyncLazy
2425
import kotlinx.coroutines.sync.Mutex
2526
import kotlinx.coroutines.sync.withLock
27+
import kotlin.coroutines.coroutineContext
2628
import kotlin.time.Duration.Companion.seconds
2729

2830
private const val CREDENTIALS_BASE_PATH: String = "/latest/meta-data/iam/security-credentials"
@@ -52,7 +54,6 @@ public class ImdsCredentialsProvider(
5254
private val platformProvider: PlatformEnvironProvider = Platform,
5355
private val clock: Clock = Clock.System,
5456
) : CredentialsProvider, Closeable {
55-
private val logger = Logger.getLogger<ImdsCredentialsProvider>()
5657
private var previousCredentials: Credentials? = null
5758

5859
// the time to refresh the Credentials. If set, it will take precedence over the Credentials' expiration time
@@ -97,7 +98,7 @@ public class ImdsCredentialsProvider(
9798
return when (val resp = deserializeJsonCredentials(deserializer)) {
9899
is JsonCredentialsResponse.SessionCredentials -> {
99100
nextRefresh = if (resp.expiration < clock.now()) {
100-
logger.warn {
101+
coroutineContext.warn<ImdsCredentialsProvider> {
101102
"Attempting credential expiration extension due to a credential service availability issue. " +
102103
"A refresh of these credentials will be attempted again in " +
103104
"${ DEFAULT_CREDENTIALS_REFRESH_SECONDS / 60 } minutes."
@@ -137,7 +138,10 @@ public class ImdsCredentialsProvider(
137138
client.value.get(CREDENTIALS_BASE_PATH)
138139
} catch (ex: EC2MetadataError) {
139140
if (ex.statusCode == HttpStatusCode.NotFound.value) {
140-
logger.info { "Received 404 from IMDS when loading profile information. Hint: This instance may not have an IAM role associated." }
141+
coroutineContext.info<ImdsCredentialsProvider> {
142+
"Received 404 from IMDS when loading profile information. Hint: This instance may not have an " +
143+
"IAM role associated."
144+
}
141145
}
142146
throw ex
143147
}

aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/ProfileCredentialsProvider.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ import aws.sdk.kotlin.runtime.region.resolveRegion
1616
import aws.smithy.kotlin.runtime.auth.awscredentials.Credentials
1717
import aws.smithy.kotlin.runtime.auth.awscredentials.CredentialsProvider
1818
import aws.smithy.kotlin.runtime.http.engine.HttpClientEngine
19+
import aws.smithy.kotlin.runtime.http.operation.getLogger
1920
import aws.smithy.kotlin.runtime.io.Closeable
20-
import aws.smithy.kotlin.runtime.logging.Logger
2121
import aws.smithy.kotlin.runtime.time.TimestampFormat
2222
import aws.smithy.kotlin.runtime.util.LazyAsyncValue
2323
import aws.smithy.kotlin.runtime.util.Platform
2424
import aws.smithy.kotlin.runtime.util.PlatformProvider
2525
import aws.smithy.kotlin.runtime.util.asyncLazy
26+
import kotlin.coroutines.coroutineContext
2627

2728
/**
2829
* A [CredentialsProvider] that gets credentials from a profile in `~/.aws/config` or the shared credentials
@@ -94,7 +95,7 @@ public class ProfileCredentialsProvider(
9495
)
9596

9697
override suspend fun getCredentials(): Credentials {
97-
val logger = Logger.getLogger<ProfileCredentialsProvider>()
98+
val logger = coroutineContext.getLogger<ProfileCredentialsProvider>()
9899
val source = resolveConfigSource(platformProvider, profileName)
99100
logger.debug { "Loading credentials from profile `${source.profile}`" }
100101
val profiles = loadAwsProfiles(platformProvider, source)

aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/SsoCredentialsProvider.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ import aws.smithy.kotlin.runtime.serde.json.*
1717
import aws.smithy.kotlin.runtime.time.Clock
1818
import aws.smithy.kotlin.runtime.time.Instant
1919
import aws.smithy.kotlin.runtime.time.fromEpochMilliseconds
20+
import aws.smithy.kotlin.runtime.tracing.*
2021
import aws.smithy.kotlin.runtime.util.*
22+
import kotlin.coroutines.coroutineContext
2123

2224
private const val PROVIDER_NAME = "SSO"
2325

@@ -95,11 +97,16 @@ public class SsoCredentialsProvider public constructor(
9597
) : CredentialsProvider {
9698

9799
override suspend fun getCredentials(): Credentials {
100+
val traceSpan = coroutineContext.traceSpan
101+
val logger = traceSpan.logger<SsoCredentialsProvider>()
102+
103+
logger.trace { "Attempting to load token file" }
98104
val token = loadTokenFile()
99105

100106
val client = SsoClient {
101107
region = ssoRegion
102108
httpClientEngine = this@SsoCredentialsProvider.httpClientEngine
109+
tracer = traceSpan.asNestedTracer("SSO-")
103110
}
104111

105112
val resp = try {

aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/StsAssumeRoleCredentialsProvider.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ import aws.sdk.kotlin.runtime.config.resolve
1313
import aws.smithy.kotlin.runtime.auth.awscredentials.Credentials
1414
import aws.smithy.kotlin.runtime.auth.awscredentials.CredentialsProvider
1515
import aws.smithy.kotlin.runtime.http.engine.HttpClientEngine
16-
import aws.smithy.kotlin.runtime.logging.Logger
1716
import aws.smithy.kotlin.runtime.time.Instant
1817
import aws.smithy.kotlin.runtime.time.TimestampFormat
1918
import aws.smithy.kotlin.runtime.time.epochMilliseconds
19+
import aws.smithy.kotlin.runtime.tracing.*
2020
import aws.smithy.kotlin.runtime.util.Platform
2121
import aws.smithy.kotlin.runtime.util.PlatformEnvironProvider
22+
import kotlin.coroutines.coroutineContext
2223
import kotlin.time.Duration
2324
import kotlin.time.Duration.Companion.seconds
2425

@@ -55,7 +56,8 @@ public class StsAssumeRoleCredentialsProvider(
5556
) : CredentialsProvider {
5657

5758
override suspend fun getCredentials(): Credentials {
58-
val logger = Logger.getLogger<StsAssumeRoleCredentialsProvider>()
59+
val traceSpan = coroutineContext.traceSpan
60+
val logger = traceSpan.logger<StsAssumeRoleCredentialsProvider>()
5961
logger.debug { "retrieving assumed credentials" }
6062

6163
// NOTE: multi region access points require regional STS endpoints
@@ -64,6 +66,7 @@ public class StsAssumeRoleCredentialsProvider(
6466
region = provider.region ?: GLOBAL_STS_PARTITION_ENDPOINT
6567
credentialsProvider = provider.credentialsProvider
6668
httpClientEngine = provider.httpClientEngine
69+
tracer = traceSpan.asNestedTracer("STS-")
6770
}
6871

6972
val resp = try {

0 commit comments

Comments
 (0)