Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
c05c29d
Extract lambda-natchez module
alexcardell Feb 22, 2024
8d84619
Remove natchez-core dependency from lambda module
alexcardell Feb 22, 2024
2862dff
Add lambda-otel4s module
alexcardell Feb 23, 2024
ad9ef67
Use SqsEvent for attributes, not SqsRecord
alexcardell Feb 23, 2024
328000b
Add otel4s-sdk example
alexcardell Feb 23, 2024
ed29cea
re-run prePR
alexcardell Feb 23, 2024
e759554
Remove resolvers
alexcardell Feb 23, 2024
ad6c45e
Add otel4s TracedHandler tests
alexcardell Feb 27, 2024
25ef4e2
Rework package structure
alexcardell Feb 27, 2024
c932050
prePR
alexcardell Feb 27, 2024
b64efb1
Swap tests from SDK to oteljava
alexcardell Mar 12, 2024
09a3ef8
Run prePR
alexcardell Mar 12, 2024
f36f069
Add back extra JVM test
alexcardell Mar 12, 2024
de2b260
Add OtelJava JVM example
alexcardell Mar 12, 2024
ca04346
Update otel4s to 0.6.0
alexcardell Apr 18, 2024
ecd17cf
Simplify for-comp
alexcardell Apr 18, 2024
0a68750
Fix headers
alexcardell Apr 18, 2024
29aecf7
Remove semconv-experimental
alexcardell Apr 19, 2024
8bd5eba
Add attributes for other events
alexcardell Apr 19, 2024
621e8e1
Remove unused imports
alexcardell Apr 19, 2024
ed1d2ce
Add http4s-otel4s-middleware to example
alexcardell May 8, 2024
4950af2
Fix import order
alexcardell May 8, 2024
9a1d4a4
use otel4s-sdk-trace-testkit to run tests across all platforms
iRevive May 10, 2024
1f995b6
Move TracedHandlerSuite to JVM
alexcardell Sep 15, 2024
3f541f6
Update workflows
alexcardell Sep 15, 2024
a0252cf
Swap module order
alexcardell Sep 15, 2024
f8b4f52
Fix TracedHandlerSuite class name
alexcardell Sep 15, 2024
c0a1919
Add JS TracedHandler suite
alexcardell Sep 15, 2024
dacbcb7
Remove unused imports
alexcardell Sep 15, 2024
e7ad6e7
Update base version
alexcardell Sep 15, 2024
5e277a1
Update otel4s to 0.8
alexcardell Sep 15, 2024
82408eb
Lambda otel4s: test span attributes
iRevive Sep 16, 2024
5092bf7
Format
alexcardell Sep 16, 2024
c29d0a4
Swap List[Attribute[_]] to Attributes
alexcardell Sep 16, 2024
288e04e
Remove unused import
alexcardell Sep 16, 2024
eca13ff
Remove unused import
alexcardell Sep 16, 2024
ec4ded6
Add LambdaContextAttributes test
alexcardell Sep 16, 2024
ada7d29
Add LambdaMessageAttributesTest
alexcardell Sep 16, 2024
7289d13
Deduplicate examples module settings keys
alexcardell Sep 16, 2024
3c299b8
Make otel4s attribute utilities package private
alexcardell Sep 16, 2024
de0ab57
Remove _root_ from example imports
alexcardell Sep 16, 2024
5f7db04
Fix example
alexcardell Sep 16, 2024
0ad05e9
Remove http4s-otel4s-middleware
alexcardell Sep 16, 2024
3ead38f
Bump otel to 0.9
alexcardell Sep 16, 2024
1542720
Fix 0.9 bump
alexcardell Sep 16, 2024
7af71ab
Move KernelSources to KernelSource companion
alexcardell Sep 26, 2024
1a6d6a3
Remove Event parameter from TracedHandler
alexcardell Sep 29, 2024
0b8d4cc
Use shared trace handler suite
alexcardell Sep 29, 2024
44a0aaf
Add v0.4.0 rewrites for natchez module
alexcardell Sep 29, 2024
0f14301
Fix formatting
alexcardell Sep 29, 2024
7f433d8
Add scalafix v0.4.0 rewrite input/output
alexcardell Sep 29, 2024
a5bf437
Split 0.3.0 and 0.4.0 rewrite rules into subprojects
alexcardell Sep 30, 2024
480dfcf
Update workflows
alexcardell Sep 30, 2024
8b0c5ff
Fix scalafix 0.4.0 rewrites test
alexcardell Sep 30, 2024
0f985ad
Remove 0.3.0 migrations
alexcardell Sep 30, 2024
352295b
Remove unused examples imports
alexcardell Oct 1, 2024
ed8be15
Rename EventSpanAttributes -> EventAttributeSources
alexcardell Oct 4, 2024
7eddd69
Add http4s-otel4s-middleware
alexcardell Jan 16, 2025
3e421af
Simplify otel attributes file structure
alexcardell Jan 16, 2025
d16a090
Fix imports
alexcardell Jan 16, 2025
0ff2142
Update example
alexcardell Oct 21, 2025
33591aa
Fix munit-cats-effect dependency reference
alexcardell Oct 22, 2025
4606aac
Fix fixture
alexcardell Oct 22, 2025
7dd11a9
fix deprecation
alexcardell Oct 23, 2025
f8c232b
Update mergify
alexcardell Nov 24, 2025
2aea5e0
Bump
alexcardell Apr 7, 2026
ceae75d
fmt
alexcardell Apr 8, 2026
e6f6cd2
Fix lambda plugin scala version
alexcardell Apr 8, 2026
544cea7
Add comment explaining semanticdb
alexcardell Apr 8, 2026
d96fbc0
more semantic conventions
alexcardell Apr 20, 2026
8fa46a7
Fix unused import
alexcardell Apr 24, 2026
88d59af
bump otel4s
alexcardell Apr 24, 2026
9594341
Bump to 1.0.0
alexcardell May 11, 2026
e76ea43
Change input implicit to TracerProvider
alexcardell Sep 28, 2026
43a268e
Fix tupling
alexcardell Sep 28, 2026
1b1aa67
Regenerate GitHub Actions workflow
alexcardell Oct 12, 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 google-cloud/js/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 google-cloud/jvm/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 google-cloud/js/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 google-cloud/jvm/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 google-cloud/js/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 google-cloud/jvm/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 google-cloud/js/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 google-cloud/jvm/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 @@ -76,6 +76,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
63 changes: 51 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"
val otel4sSdkVersion = "0.19.0"

lazy val commonSettings = Seq(
crossScalaVersions := Seq(Scala3, Scala213)
Expand All @@ -75,6 +79,8 @@ lazy val root =
lambda,
lambdaHttp4s,
lambdaCloudFormationCustomResource,
lambdaNatchez,
lambdaOtel4s,
googleCloudHttp4s,
googleCloud,
examples,
Expand All @@ -96,7 +102,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 @@ -182,6 +188,37 @@ 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"))
.enablePlugins(BuildInfoPlugin)
.settings(
name := "feral-lambda-otel4s",
buildInfoPackage := "feral.lambda.otel4s",
buildInfoKeys := Seq[BuildInfoKey](version),
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 @@ -190,21 +227,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"
)
)
.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 @@ -225,22 +263,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,85 @@
/*
* 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.effect.Resource
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 middleware = ClientMiddleware.builder[IO](spanDataProvider).build

middleware.map((_, tp))
}
.flatMap {
case (middleware, tracerProvider) =>
implicit val tp: TracerProvider[IO] = tracerProvider

for {
client <- EmberClientBuilder.default[IO].build.map(middleware.wrapClient)
tracer <- Resource.eval(tp.get("com.example"))
} yield { implicit inv: Invocation[IO, SqsEvent] =>
implicit val t: Tracer[IO] = tracer
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