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

WIP: opentelemetry with HTTP client, too #1386

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions action-binding-generator/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ version = rootProject.version
dependencies {
implementation("com.squareup:kotlinpoet:1.16.0")
implementation("com.charleskorn.kaml:kaml:0.58.0")
implementation(platform("io.ktor:ktor-bom:2.3.10"))
implementation("io.ktor:ktor-client-core")
implementation("io.ktor:ktor-client-cio")
implementation("io.ktor:ktor-client-content-negotiation")
implementation(projects.sharedInternal)

testImplementation(projects.githubWorkflowsKt)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import io.github.typesafegithub.workflows.actionbindinggenerator.typing.provideT
import io.github.typesafegithub.workflows.actionbindinggenerator.utils.removeTrailingWhitespacesForEachLine
import io.github.typesafegithub.workflows.actionbindinggenerator.utils.toCamelCase
import io.github.typesafegithub.workflows.actionbindinggenerator.utils.toKotlinPackageName
import io.ktor.client.HttpClient
import java.nio.file.Path

public data class ActionBinding(
Expand Down Expand Up @@ -71,14 +72,15 @@ public fun ActionCoords.generateBinding(
metadata: Metadata? = null,
inputTypings: Pair<Map<String, Typing>, TypingActualSource?>? = null,
clientType: ClientType = ClientType.BUNDLED_WITH_LIB,
httpClient: HttpClient,
): ActionBinding? {
require(this.version.removePrefix("v").toIntOrNull() != null) {
"Only major versions are supported, and '${this.version}' was given!"
}
val metadataResolved = metadata ?: this.fetchMetadata(metadataRevision) ?: return null
val metadataResolved = metadata ?: this.fetchMetadata(metadataRevision, httpClient) ?: return null
val metadataProcessed = metadataResolved.removeDeprecatedInputsIfNameClash()

val inputTypingsResolved = inputTypings ?: this.provideTypes(metadataRevision)
val inputTypingsResolved = inputTypings ?: this.provideTypes(metadataRevision, httpClient)

val className = this.buildActionClassName(includeVersion = clientType == ClientType.BUNDLED_WITH_LIB)
val actionBindingSourceCode =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import io.github.typesafegithub.workflows.actionbindinggenerator.domain.FromLock
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.MetadataRevision
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.NewestForVersion
import io.github.typesafegithub.workflows.actionbindinggenerator.utils.myYaml
import io.ktor.client.HttpClient
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import java.io.IOException
Expand Down Expand Up @@ -53,6 +54,7 @@ internal val ActionCoords.gitHubUrl: String get() = "https://github.com/$owner/$

public fun ActionCoords.fetchMetadata(
metadataRevision: MetadataRevision,
httpClient: HttpClient,
fetchUri: (URI) -> String = ::fetchUri,
): Metadata? {
val gitRef =
Expand All @@ -75,5 +77,3 @@ public fun ActionCoords.fetchMetadata(

private fun ActionCoords.getCommitHashFromFileSystem(): String =
Path.of("actions", owner, name.substringBefore('/'), version, "commit-hash.txt").toFile().readText().trim()

internal fun fetchUri(uri: URI): String = uri.toURL().readText()
8 changes: 8 additions & 0 deletions jit-binding-server/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ dependencies {
implementation(platform("io.ktor:ktor-bom:2.3.10"))
implementation("io.ktor:ktor-server-core")
implementation("io.ktor:ktor-server-netty")
implementation("io.ktor:ktor-client-core")
implementation("io.ktor:ktor-client-cio")
implementation("io.ktor:ktor-client-content-negotiation")
implementation("io.ktor:ktor-serialization-kotlinx-json")
implementation("io.opentelemetry.instrumentation:opentelemetry-ktor-2.0:2.3.0-alpha")
implementation("io.opentelemetry:opentelemetry-sdk:1.37.0")
implementation("io.opentelemetry:opentelemetry-exporter-otlp:1.37.0")
implementation("io.opentelemetry:opentelemetry-exporter-logging:1.37.0")
implementation("io.github.reactivecircus.cache4k:cache4k:0.13.0")
implementation("ch.qos.logback:logback-classic:1.5.5")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ import io.github.typesafegithub.workflows.mavenbinding.JarArtifact
import io.github.typesafegithub.workflows.mavenbinding.TextArtifact
import io.github.typesafegithub.workflows.mavenbinding.buildPackageArtifacts
import io.github.typesafegithub.workflows.mavenbinding.buildVersionArtifacts
import io.ktor.client.HttpClient
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.application.call
import io.ktor.server.application.install
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
import io.ktor.server.response.respondBytes
Expand All @@ -19,15 +23,36 @@ import io.ktor.server.routing.get
import io.ktor.server.routing.head
import io.ktor.server.routing.route
import io.ktor.server.routing.routing
import io.opentelemetry.instrumentation.ktor.v2_0.client.KtorClientTracing
import io.opentelemetry.instrumentation.ktor.v2_0.server.KtorServerTracing
import kotlinx.serialization.json.Json
import kotlin.time.Duration.Companion.hours

fun main() {
val bindingsCache =
Cache.Builder<ActionCoords, Result<Map<String, Artifact>>>()
.expireAfterAccess(1.hours)
.build()
val openTelemetry = OpenTelemetryConfig.config("jit-bindings").newInstance()

val httpClient =
HttpClient {
install(ContentNegotiation) {
json(
Json {
ignoreUnknownKeys = true
},
)
}
install(KtorClientTracing) {
setOpenTelemetry(openTelemetry)
}
}

embeddedServer(Netty, port = 8080) {
install(KtorServerTracing) {
setOpenTelemetry(openTelemetry)
}
routing {
route("/binding/{owner}/{name}/{version}/{file}") {
get {
Expand All @@ -43,7 +68,7 @@ fun main() {
println("➡️ Requesting ${actionCoords.prettyPrint}")
val bindingArtifacts =
bindingsCache.get(actionCoords) {
actionCoords.buildVersionArtifacts()?.let {
actionCoords.buildVersionArtifacts(httpClient)?.let {
Result.success(it)
} ?: Result.failure(object : Throwable() {})
}.getOrNull()
Expand Down Expand Up @@ -82,7 +107,7 @@ fun main() {
)
val bindingArtifacts =
bindingsCache.get(actionCoords) {
actionCoords.buildVersionArtifacts()?.let {
actionCoords.buildVersionArtifacts(httpClient)?.let {
Result.success(it)
} ?: Result.failure(object : Throwable() {})
}.getOrNull()
Expand Down Expand Up @@ -110,7 +135,7 @@ fun main() {
name = name,
version = "irrelevant",
)
val bindingArtifacts = actionCoords.buildPackageArtifacts(githubToken = System.getenv("GITHUB_TOKEN"))
val bindingArtifacts = actionCoords.buildPackageArtifacts(githubToken = System.getenv("GITHUB_TOKEN"), httpClient)
if (file in bindingArtifacts) {
when (val artifact = bindingArtifacts[file]) {
is String -> call.respondText(artifact)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package io.github.typesafegithub.workflows.jitbindingserver

import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator
import io.opentelemetry.context.propagation.ContextPropagators
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter
import io.opentelemetry.sdk.OpenTelemetrySdk
import io.opentelemetry.sdk.logs.SdkLoggerProvider
import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor
import io.opentelemetry.sdk.metrics.SdkMeterProvider
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader
import io.opentelemetry.sdk.resources.Resource
import io.opentelemetry.sdk.trace.SdkTracerProvider
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor
import java.util.concurrent.TimeUnit

// docker run --rm \
// -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
// -p 16686:16686 \
// -p 4317:4317 \
// -p 4318:4318 \
// -p 9411:9411 \
// jaegertracing/all-in-one:latest
data class OpenTelemetryConfig(
val endpointConfig: String,
val defaultScopeName: String,
val serviceName: String,
) {
fun newInstance(): OpenTelemetry {
val spanExporter =
OtlpGrpcSpanExporter.builder()
.setEndpoint(endpointConfig)
.setTimeout(30, TimeUnit.SECONDS)
.build()
// @Suppress("DEPRECATION")
// val spanExporter = LoggingSpanExporter()

val metricExporter = OtlpGrpcMetricExporter.builder().build()
// @Suppress("DEPRECATION")
// val metricExporter = LoggingMetricExporter()

val recordExporter = OtlpGrpcLogRecordExporter.builder().build()
// val recordExporter = SystemOutLogRecordExporter.create()

val resource =
Resource.getDefault()
.toBuilder()
.put(AttributeKey.stringKey("service.name"), serviceName)
.build()

val tracerProvider =
SdkTracerProvider.builder()
.addSpanProcessor(BatchSpanProcessor.builder(spanExporter).build())
.setResource(resource)
.build()

val meterProvider =
SdkMeterProvider.builder()
.registerMetricReader(
PeriodicMetricReader.builder(metricExporter).build(),
)
.setResource(resource)
.build()

val loggerProvider =
SdkLoggerProvider.builder()
.addLogRecordProcessor(
BatchLogRecordProcessor.builder(recordExporter).build(),
)
.setResource(resource)
.build()

val openTelemetry =
OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
.setMeterProvider(meterProvider)
.setLoggerProvider(loggerProvider)
.setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
.buildAndRegisterGlobal()

Runtime.getRuntime().addShutdownHook(Thread { openTelemetry.close() })
return openTelemetry
}

companion object {
fun config(serviceName: String) =
OpenTelemetryConfig(
endpointConfig = "http://localhost:4317",
defaultScopeName = "com.sample",
serviceName = serviceName,
)
}
}
2 changes: 2 additions & 0 deletions maven-binding-builder/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ dependencies {
implementation("io.ktor:ktor-client-cio")
implementation("io.ktor:ktor-client-content-negotiation")
implementation("io.ktor:ktor-serialization-kotlinx-json")
implementation("io.opentelemetry.instrumentation:opentelemetry-ktor-2.0:2.3.0-alpha")
implementation("io.opentelemetry:opentelemetry-sdk:1.37.0")

runtimeOnly(projects.githubWorkflowsKt)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import io.github.typesafegithub.workflows.actionbindinggenerator.domain.NewestFo
import io.github.typesafegithub.workflows.actionbindinggenerator.generation.ActionBinding
import io.github.typesafegithub.workflows.actionbindinggenerator.generation.ClientType
import io.github.typesafegithub.workflows.actionbindinggenerator.generation.generateBinding
import io.ktor.client.HttpClient
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
Expand All @@ -24,8 +25,9 @@ internal fun buildJar(
owner: String,
name: String,
version: String,
httpClient: HttpClient,
): ByteArray? {
val binding = generateBinding(owner = owner, name = name, version = version) ?: return null
val binding = generateBinding(owner = owner, name = name, version = version, httpClient) ?: return null
val pathWithJarContents = binding.compileBinding()
val byteArrayOutputStream = ByteArrayOutputStream()
byteArrayOutputStream.createZipFile(pathWithJarContents)
Expand All @@ -36,6 +38,7 @@ private fun generateBinding(
owner: String,
name: String,
version: String,
httpClient: HttpClient,
): ActionBinding? {
val actionCoords =
ActionCoords(
Expand All @@ -46,6 +49,7 @@ private fun generateBinding(
return actionCoords.generateBinding(
metadataRevision = NewestForVersion,
clientType = ClientType.VERSIONED_JAR,
httpClient = httpClient,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@ package io.github.typesafegithub.workflows.mavenbinding

import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.request.bearerAuth
import io.ktor.client.request.get
import io.ktor.serialization.kotlinx.json.json
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import java.time.Instant
import java.time.ZoneId
import java.time.format.DateTimeFormatter
Expand All @@ -16,13 +13,14 @@ internal suspend fun buildMavenMetadataFile(
owner: String,
name: String,
githubToken: String,
httpClient: HttpClient,
): String {
val lastUpdated =
DateTimeFormatter.ofPattern("yyyyMMddHHmmss")
.withZone(ZoneId.systemDefault())
.format(Instant.now())
val availableMajorVersions =
fetchAvailableVersions(owner = owner, name = name.substringBefore("__"), githubToken = githubToken)
fetchAvailableVersions(owner = owner, name = name.substringBefore("__"), githubToken = githubToken, httpClient = httpClient)
.filter { it.removePrefix("v").toIntOrNull() != null }
val newest = availableMajorVersions.maxBy { it.removePrefix("v") }
return """
Expand All @@ -48,33 +46,23 @@ private suspend fun fetchAvailableVersions(
owner: String,
name: String,
githubToken: String,
httpClient: HttpClient,
): List<String> =
listOf(
apiTagsUrl(owner = owner, name = name),
apiBranchesUrl(owner = owner, name = name),
).flatMap { url -> fetchGithubRefs(url, githubToken) }
).flatMap { url -> fetchGithubRefs(url, githubToken, httpClient) }
.map { it.ref.substringAfterLast("/") }

private suspend fun fetchGithubRefs(
url: String,
githubToken: String,
httpClient: HttpClient,
): List<GithubRef> =
httpClient.get(urlString = url) {
bearerAuth(githubToken)
}.body()

private val httpClient by lazy {
HttpClient {
install(ContentNegotiation) {
json(
Json {
ignoreUnknownKeys = true
},
)
}
}
}

private fun apiTagsUrl(
owner: String,
name: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package io.github.typesafegithub.workflows.mavenbinding

import io.github.typesafegithub.workflows.actionbindinggenerator.domain.ActionCoords
import io.ktor.client.HttpClient

suspend fun ActionCoords.buildPackageArtifacts(githubToken: String): Map<String, String> {
val mavenMetadata = buildMavenMetadataFile(owner = owner, name = name, githubToken = githubToken)
suspend fun ActionCoords.buildPackageArtifacts(
githubToken: String,
httpClient: HttpClient,
): Map<String, String> {
val mavenMetadata = buildMavenMetadataFile(owner = owner, name = name, githubToken = githubToken, httpClient)
return mapOf(
"maven-metadata.xml" to mavenMetadata,
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.typesafegithub.workflows.mavenbinding

import io.github.typesafegithub.workflows.actionbindinggenerator.domain.ActionCoords
import io.ktor.client.HttpClient
import java.security.MessageDigest

sealed interface Artifact
Expand All @@ -9,8 +10,8 @@ data class TextArtifact(val data: String) : Artifact

data class JarArtifact(val data: ByteArray) : Artifact

fun ActionCoords.buildVersionArtifacts(): Map<String, Artifact>? {
val jar = buildJar(owner = owner, name = name.replace("__", "/"), version = version) ?: return null
fun ActionCoords.buildVersionArtifacts(httpClient: HttpClient): Map<String, Artifact>? {
val jar = buildJar(owner = owner, name = name.replace("__", "/"), version = version, httpClient) ?: return null
val pom = buildPomFile(owner = owner, name = name.replace("__", "/"), version = version)
val module = buildModuleFile(owner = owner, name = name.replace("__", "/"), version = version)
return mapOf(
Expand Down
Loading