Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
bdd04ab
Extract lambda-natchez module
alexcardell Feb 22, 2024
e9e4f2d
Remove natchez-core dependency from lambda module
alexcardell Feb 22, 2024
c9e990f
Add lambda-otel4s module
alexcardell Feb 23, 2024
1b51a90
Use SqsEvent for attributes, not SqsRecord
alexcardell Feb 23, 2024
80c86f3
Add otel4s-sdk example
alexcardell Feb 23, 2024
e455e8e
re-run prePR
alexcardell Feb 23, 2024
8e16c45
Remove resolvers
alexcardell Feb 23, 2024
39de366
Add otel4s TracedHandler tests
alexcardell Feb 27, 2024
962db5b
Rework package structure
alexcardell Feb 27, 2024
99fe831
prePR
alexcardell Feb 27, 2024
bc6ca86
Swap tests from SDK to oteljava
alexcardell Mar 12, 2024
8693872
Run prePR
alexcardell Mar 12, 2024
c1603fe
Add back extra JVM test
alexcardell Mar 12, 2024
b777ad5
Add OtelJava JVM example
alexcardell Mar 12, 2024
250d028
Update otel4s to 0.6.0
alexcardell Apr 18, 2024
c759e46
Simplify for-comp
alexcardell Apr 18, 2024
4dcedfb
Fix headers
alexcardell Apr 18, 2024
5d2fe55
Remove semconv-experimental
alexcardell Apr 19, 2024
ed653c4
Add attributes for other events
alexcardell Apr 19, 2024
7781210
Remove unused imports
alexcardell Apr 19, 2024
584c243
Add http4s-otel4s-middleware to example
alexcardell May 8, 2024
02f2143
Fix import order
alexcardell May 8, 2024
5faecb0
use otel4s-sdk-trace-testkit to run tests across all platforms
iRevive May 10, 2024
844fddf
Move TracedHandlerSuite to JVM
alexcardell Sep 15, 2024
bfff8f2
Update workflows
alexcardell Sep 15, 2024
7310357
Swap module order
alexcardell Sep 15, 2024
f0f7585
Fix TracedHandlerSuite class name
alexcardell Sep 15, 2024
37cc33f
Add JS TracedHandler suite
alexcardell Sep 15, 2024
29b51c2
Remove unused imports
alexcardell Sep 15, 2024
5547fd2
Update base version
alexcardell Sep 15, 2024
ad58bff
Update otel4s to 0.8
alexcardell Sep 15, 2024
c81279c
Lambda otel4s: test span attributes
iRevive Sep 16, 2024
271b937
Format
alexcardell Sep 16, 2024
a54e522
Swap List[Attribute[_]] to Attributes
alexcardell Sep 16, 2024
ff87ea8
Remove unused import
alexcardell Sep 16, 2024
25b0cf8
Remove unused import
alexcardell Sep 16, 2024
f2622a1
Add LambdaContextAttributes test
alexcardell Sep 16, 2024
e07ba78
Add LambdaMessageAttributesTest
alexcardell Sep 16, 2024
5b03a45
Deduplicate examples module settings keys
alexcardell Sep 16, 2024
913bfb1
Make otel4s attribute utilities package private
alexcardell Sep 16, 2024
11ebd3e
Remove _root_ from example imports
alexcardell Sep 16, 2024
8d9a599
Fix example
alexcardell Sep 16, 2024
ea82a43
Remove http4s-otel4s-middleware
alexcardell Sep 16, 2024
dc110c4
Bump otel to 0.9
alexcardell Sep 16, 2024
691f832
Fix 0.9 bump
alexcardell Sep 16, 2024
d08a948
Move KernelSources to KernelSource companion
alexcardell Sep 26, 2024
5dc42c1
Remove Event parameter from TracedHandler
alexcardell Sep 29, 2024
86ae33e
Use shared trace handler suite
alexcardell Sep 29, 2024
2b398e8
Add v0.4.0 rewrites for natchez module
alexcardell Sep 29, 2024
fcd9a67
Fix formatting
alexcardell Sep 29, 2024
fc41dcb
Add scalafix v0.4.0 rewrite input/output
alexcardell Sep 29, 2024
926baa0
Split 0.3.0 and 0.4.0 rewrite rules into subprojects
alexcardell Sep 30, 2024
6ef9c20
Update workflows
alexcardell Sep 30, 2024
ceae158
Fix scalafix 0.4.0 rewrites test
alexcardell Sep 30, 2024
dae7207
Remove 0.3.0 migrations
alexcardell Sep 30, 2024
66a3d93
Remove unused examples imports
alexcardell Oct 1, 2024
c16c20a
Rename EventSpanAttributes -> EventAttributeSources
alexcardell Oct 4, 2024
5cb414e
Add http4s-otel4s-middleware
alexcardell Jan 16, 2025
ffc962e
Simplify otel attributes file structure
alexcardell Jan 16, 2025
edee180
Fix imports
alexcardell Jan 16, 2025
5e628d7
Update example
alexcardell Oct 21, 2025
e23b16f
Fix munit-cats-effect dependency reference
alexcardell Oct 22, 2025
7abe21e
Fix fixture
alexcardell Oct 22, 2025
e68bfeb
fix deprecation
alexcardell Oct 23, 2025
432cc4b
Update mergify
alexcardell Nov 24, 2025
42278bf
Bump
alexcardell Apr 7, 2026
4a18338
fmt
alexcardell Apr 8, 2026
b5c6efc
Fix lambda plugin scala version
alexcardell Apr 8, 2026
5eacd1b
Add comment explaining semanticdb
alexcardell Apr 8, 2026
e62dee3
more semantic conventions
alexcardell Apr 20, 2026
52301c4
Fix unused import
alexcardell Apr 24, 2026
c34e9b0
bump otel4s
alexcardell Apr 24, 2026
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: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,11 @@ jobs:

- name: Make target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
run: mkdir -p lambda-cloudformation-custom-resource/.js/target lambda-http4s/.jvm/target unidocs/target lambda-http4s/.js/target lambda/js/target scalafix/rules/target lambda/jvm/target sbt-lambda/target google-cloud-http4s/jvm/target lambda-cloudformation-custom-resource/.jvm/target google-cloud-http4s/js/target project/target
run: mkdir -p lambda-natchez/jvm/target lambda-natchez/js/target lambda-cloudformation-custom-resource/.js/target lambda-http4s/.jvm/target unidocs/target lambda-http4s/.js/target lambda/js/target scalafix/rules/target lambda/jvm/target lambda-otel4s/jvm/target sbt-lambda/target lambda-otel4s/js/target google-cloud-http4s/jvm/target lambda-cloudformation-custom-resource/.jvm/target google-cloud-http4s/js/target project/target

- name: Compress target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
run: tar cf targets.tar lambda-cloudformation-custom-resource/.js/target lambda-http4s/.jvm/target unidocs/target lambda-http4s/.js/target lambda/js/target scalafix/rules/target lambda/jvm/target sbt-lambda/target google-cloud-http4s/jvm/target lambda-cloudformation-custom-resource/.jvm/target google-cloud-http4s/js/target project/target
run: tar cf targets.tar lambda-natchez/jvm/target lambda-natchez/js/target lambda-cloudformation-custom-resource/.js/target lambda-http4s/.jvm/target unidocs/target lambda-http4s/.js/target lambda/js/target scalafix/rules/target lambda/jvm/target lambda-otel4s/jvm/target sbt-lambda/target lambda-otel4s/js/target google-cloud-http4s/jvm/target lambda-cloudformation-custom-resource/.jvm/target google-cloud-http4s/js/target project/target

- name: Upload target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
Expand Down
16 changes: 16 additions & 0 deletions .mergify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,22 @@ pull_request_rules:
add:
- lambda-http4s
remove: []
- name: Label lambda-natchez PRs
conditions:
- files~=^lambda-natchez/
actions:
label:
add:
- lambda-natchez
remove: []
- name: Label lambda-otel4s PRs
conditions:
- files~=^lambda-otel4s/
actions:
label:
add:
- lambda-otel4s
remove: []
- name: Label output PRs
conditions:
- files~=^scalafix/output/
Expand Down
60 changes: 48 additions & 12 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import com.typesafe.tools.mima.core._

name := "feral"

ThisBuild / tlBaseVersion := "0.3"
ThisBuild / tlBaseVersion := "0.4"
ThisBuild / startYear := Some(2021)

ThisBuild / developers := List(
Expand All @@ -28,6 +28,8 @@ ThisBuild / developers := List(
)

ThisBuild / githubWorkflowJavaVersions := Seq("11", "17").map(JavaSpec.corretto(_))
// TODO remove when sbt-typelevel supports 2.13.18
ThisBuild / semanticdbVersion := "4.13.10"

ThisBuild / githubWorkflowBuildMatrixExclusions ++=
List("rootJS", "rootJVM").map(p => MatrixExclude(Map("project" -> p, "scala" -> "2.12"))) ++
Expand All @@ -52,7 +54,7 @@ ThisBuild / mergifyStewardConfig ~= {
}

val Scala212 = "2.12.20"
val Scala213 = "2.13.17"
val Scala213 = "2.13.18"
val Scala3 = "3.3.7"
ThisBuild / crossScalaVersions := Seq(Scala212, Scala3, Scala213)

Expand All @@ -64,6 +66,8 @@ val natchezVersion = "0.3.8"
val munitVersion = "1.2.0"
val munitCEVersion = "2.1.0"
val scalacheckEffectVersion = "2.1.0-RC1"
val otel4sVersion = "1.0.0-RC1"
val otel4sSdkVersion = "0.19.0-RC1"

lazy val commonSettings = Seq(
crossScalaVersions := Seq(Scala3, Scala213)
Expand All @@ -75,6 +79,8 @@ lazy val root =
lambda,
lambdaHttp4s,
lambdaCloudFormationCustomResource,
lambdaNatchez,
lambdaOtel4s,
googleCloudHttp4s,
examples,
unidocs
Expand All @@ -95,7 +101,7 @@ lazy val lambda = crossProject(JSPlatform, JVMPlatform)
name := "feral-lambda",
libraryDependencies ++= Seq(
"org.typelevel" %%% "cats-effect" % catsEffectVersion,
"org.tpolecat" %%% "natchez-core" % natchezVersion,
"org.typelevel" %%% "case-insensitive" % "1.4.0",
"io.circe" %%% "circe-scodec" % circeVersion,
"io.circe" %%% "circe-jawn" % circeVersion,
"com.comcast" %%% "ip4s-core" % "3.7.0",
Expand Down Expand Up @@ -181,6 +187,34 @@ lazy val lambdaCloudFormationCustomResource = crossProject(JSPlatform, JVMPlatfo
.settings(commonSettings)
.dependsOn(lambda)

lazy val lambdaNatchez = crossProject(JSPlatform, JVMPlatform)
.in(file("lambda-natchez"))
.settings(
name := "feral-lambda-natchez",
libraryDependencies ++= Seq(
"org.tpolecat" %%% "natchez-core" % natchezVersion,
"org.scalameta" %%% "munit-scalacheck" % munitVersion % Test,
"org.typelevel" %%% "munit-cats-effect" % munitCEVersion % Test
)
)
.settings(commonSettings)
.dependsOn(lambda)

lazy val lambdaOtel4s = crossProject(JSPlatform, JVMPlatform)
.in(file("lambda-otel4s"))
.settings(
name := "feral-lambda-otel4s",
libraryDependencies ++= Seq(
"org.typelevel" %%% "otel4s-core-trace" % otel4sVersion,
"org.typelevel" %%% "otel4s-sdk-trace-testkit" % otel4sSdkVersion % Test,
"org.typelevel" %%% "otel4s-semconv-experimental" % otel4sVersion % Test,
Comment thread
alexcardell marked this conversation as resolved.
"org.scalameta" %%% "munit-scalacheck" % munitVersion % Test,
"org.typelevel" %%% "munit-cats-effect" % munitCEVersion % Test
)
)
.settings(commonSettings)
.dependsOn(lambda)

lazy val examples = crossProject(JSPlatform, JVMPlatform)
.in(file("examples"))
.settings(
Expand All @@ -189,21 +223,22 @@ lazy val examples = crossProject(JSPlatform, JVMPlatform)
"org.http4s" %%% "http4s-ember-client" % http4sVersion,
"org.tpolecat" %%% "natchez-xray" % natchezVersion,
"org.tpolecat" %%% "natchez-http4s" % "0.6.1",
"org.tpolecat" %%% "skunk-core" % "0.6.4"
"org.tpolecat" %%% "skunk-core" % "0.6.4",
"org.http4s" %%% "http4s-otel4s-middleware-trace-client" % "0.18.0-RC1"
)
)
.settings(commonSettings)
.dependsOn(lambda, lambdaHttp4s, googleCloudHttp4s)
.dependsOn(lambda, lambdaHttp4s, lambdaNatchez, lambdaOtel4s, googleCloudHttp4s)
.jvmSettings(libraryDependencies ++= Seq(
"org.typelevel" %%% "otel4s-oteljava" % otel4sVersion,
"io.opentelemetry" % "opentelemetry-sdk-extension-autoconfigure" % "1.34.1",
"com.google.cloud.functions.invoker" % "java-function-invoker" % "1.4.3"
))
.jsSettings(
scalaJSUseMainModuleInitializer := true,
Compile / mainClass := Some("feral.examples.http4sGoogleCloudHandler"),
scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) }
)
.jvmSettings(
libraryDependencies ++= Seq(
"com.google.cloud.functions.invoker" % "java-function-invoker" % "1.4.3"
)
)
.enablePlugins(NoPublishPlugin)

lazy val unidocs = project
Expand All @@ -224,22 +259,23 @@ lazy val unidocs = project
)

lazy val scalafix = tlScalafixProject
.in(file("scalafix"))
.rulesSettings(
name := "feral-scalafix",
startYear := Some(2023),
crossScalaVersions := Seq(Scala212)
)
.inputSettings(
crossScalaVersions := Seq(Scala213),
libraryDependencies += "org.typelevel" %%% "feral-lambda-http4s" % "0.2.4",
libraryDependencies += "org.typelevel" %%% "feral-lambda" % "0.3.1",
headerSources / excludeFilter := AllPassFilter
)
.inputConfigure(_.disablePlugins(ScalafixPlugin))
.outputSettings(
crossScalaVersions := Seq(Scala213),
headerSources / excludeFilter := AllPassFilter
)
.outputConfigure(_.dependsOn(lambdaHttp4s.jvm).disablePlugins(ScalafixPlugin))
.outputConfigure(_.dependsOn(lambdaNatchez.jvm).disablePlugins(ScalafixPlugin))
.testsSettings(
startYear := Some(2023),
crossScalaVersions := Seq(Scala212)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright 2021 Typelevel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package feral.examples

import cats.Monad
import cats.effect.IO
import cats.syntax.all._
import feral.lambda.INothing
import feral.lambda.IOLambda
import feral.lambda.Invocation
import feral.lambda.events.SqsEvent
import feral.lambda.events.SqsRecord
import feral.lambda.otel4s._
import org.http4s.client.Client
import org.http4s.ember.client.EmberClientBuilder
import org.http4s.otel4s.middleware.trace.client.ClientMiddleware
import org.http4s.otel4s.middleware.trace.client.ClientSpanDataProvider
import org.http4s.otel4s.middleware.trace.client.UriRedactor
import org.typelevel.otel4s.oteljava.OtelJava
import org.typelevel.otel4s.trace.Tracer
import org.typelevel.otel4s.trace.TracerProvider
import org.typelevel.scalaccompat.annotation.unused

object SqsOtelExample extends IOLambda[SqsEvent, INothing] {

def handler =
OtelJava
.autoConfigured[IO]()
.evalMap { otel =>
implicit val tp: TracerProvider[IO] = otel.tracerProvider
val otelClientRedactor = new UriRedactor.OnlyRedactUserInfo {}
val spanDataProvider = ClientSpanDataProvider.openTelemetry(otelClientRedactor)
val tracer = tp.get("com.example")
val middleware = ClientMiddleware.builder[IO](spanDataProvider).build
(middleware, tracer).tupled
}
.flatMap {
case (middleware, tracer) =>
implicit val t: Tracer[IO] = tracer

for {
client <- EmberClientBuilder.default[IO].build.map(middleware.wrapClient)
} yield { implicit inv: Invocation[IO, SqsEvent] =>
TracedHandler[IO, SqsEvent, INothing](
handleEvent[IO](client)
)
}
}

def handleEvent[F[_]: Monad: Tracer](
@unused client: Client[F]
)(implicit inv: Invocation[F, SqsEvent]): F[Option[INothing]] = inv.event.flatMap { event =>
event
.records
.traverse(record =>
Tracer[F].span("handle-record", SqsRecordAttributes(record)).surround {
handleRecord[F](record)
})
.as(None)
}

def handleRecord[F[_]: Monad: Tracer](@unused record: SqsRecord): F[Unit] = {
Tracer[F].span("some-operation").surround {
Monad[F].unit
}
}

}
13 changes: 7 additions & 6 deletions examples/shared/src/main/scala/feral/examples/Http4sLambda.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@

package feral.examples

import _root_.feral.lambda._
import _root_.feral.lambda.events._
import _root_.feral.lambda.http4s._
import _root_.feral.lambda.natchez._
import _root_.natchez.Trace
import _root_.natchez.http4s.NatchezMiddleware
import _root_.natchez.xray.XRay
import cats.effect._
import cats.effect.std.Random
import feral.lambda._
import feral.lambda.events._
import feral.lambda.http4s._
import natchez.Trace
import natchez.http4s.NatchezMiddleware
import natchez.xray.XRay
import org.http4s.HttpApp
import org.http4s.HttpRoutes
import org.http4s.client.Client
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@

package feral.examples

import _root_.feral.lambda._
import _root_.feral.lambda.events.SqsEvent
import _root_.natchez.Trace
import _root_.natchez.xray.XRay
import cats.effect._
import cats.effect.std.Random
import feral.lambda._
import feral.lambda.events.SqsEvent
import natchez.Trace
import natchez.xray.XRay
import skunk.Session

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package feral.lambda
package feral.lambda.natchez
Comment thread
alexcardell marked this conversation as resolved.

import natchez.TraceValue

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright 2021 Typelevel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package feral.lambda.natchez

import feral.lambda.events.ApiGatewayProxyEvent
import feral.lambda.events.ApiGatewayProxyEventV2
import feral.lambda.events.DynamoDbStreamEvent
import feral.lambda.events.KinesisStreamEvent
import feral.lambda.events.S3BatchEvent
import feral.lambda.events.SqsRecordAttributes
import natchez.Kernel
import org.typelevel.ci._

trait KernelSource[Event] {
def extract(event: Event): Kernel
}

object KernelSource {
@inline def apply[E](implicit ev: KernelSource[E]): ev.type = ev

def emptyKernelSource[E]: KernelSource[E] = _ => Kernel(Map.empty)

private[this] val `X-Amzn-Trace-Id` = ci"X-Amzn-Trace-Id"

implicit def apiGatewayProxyEvent: KernelSource[ApiGatewayProxyEvent] =
e => Kernel(e.headers.getOrElse(Map.empty))

implicit def apiGatewayProxyEventV2: KernelSource[ApiGatewayProxyEventV2] =
e => Kernel(e.headers)

implicit def sqsRecordAttributes: KernelSource[SqsRecordAttributes] =
a => Kernel(a.awsTraceHeader.map(`X-Amzn-Trace-Id` -> _).toMap)

implicit def s3BatchEvent: KernelSource[S3BatchEvent] = KernelSource.emptyKernelSource

@deprecated(
"See feral.lambda.events.KinesisStreamEvent deprecation",
since = "0.3.0"
)
implicit def kinesisStreamEvent: KernelSource[KinesisStreamEvent] =
KernelSource.emptyKernelSource

implicit def dynamoDbStreamEvent: KernelSource[DynamoDbStreamEvent] =
KernelSource.emptyKernelSource
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@
* limitations under the License.
*/

package feral.lambda
package feral.lambda.natchez

import cats.data.Kleisli
import cats.effect.IO
import cats.effect.kernel.MonadCancelThrow
import cats.syntax.all._
import feral.lambda.Invocation
import natchez.EntryPoint
import natchez.Span
import natchez.Trace
Expand Down
Loading
Loading