Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* 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.events

import io.circe.Decoder

// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/aws-lambda/trigger/cloudwatch-logs.d.ts
// https://docs.aws.amazon.com/lambda/latest/dg/eventsources.html#eventsources-cloudwatch-logs

sealed abstract class CloudWatchLogsEvent {
def awslogs: CloudWatchLogsEventData
}

object CloudWatchLogsEvent {

def apply(awslogs: CloudWatchLogsEventData): CloudWatchLogsEvent =
new Impl(awslogs)

implicit val decoder: Decoder[CloudWatchLogsEvent] =
Decoder.forProduct1("awslogs")(CloudWatchLogsEvent.apply)

private final case class Impl(awslogs: CloudWatchLogsEventData) extends CloudWatchLogsEvent {
override def productPrefix = "CloudWatchLogsEvent"
}
}

sealed abstract class CloudWatchLogsEventData {
def data: String
}

object CloudWatchLogsEventData {

def apply(data: String): CloudWatchLogsEventData =
new Impl(data)

private[events] implicit val decoder: Decoder[CloudWatchLogsEventData] =
Decoder.forProduct1("data")(CloudWatchLogsEventData.apply)

private final case class Impl(data: String) extends CloudWatchLogsEventData {
override def productPrefix = "CloudWatchLogsEventData"
}
}

/**
* Decoded payload after base64-decode and gzip-decompress of `CloudWatchLogsEventData.data`.
*/
sealed abstract class CloudWatchLogsDecodedData {
def owner: String
def logGroup: String
def logStream: String
def subscriptionFilters: List[String]
def messageType: String
def logEvents: List[CloudWatchLogsLogEvent]
}

object CloudWatchLogsDecodedData {

def apply(
owner: String,
logGroup: String,
logStream: String,
subscriptionFilters: List[String],
messageType: String,
logEvents: List[CloudWatchLogsLogEvent]
): CloudWatchLogsDecodedData =
new Impl(
owner,
logGroup,
logStream,
subscriptionFilters,
messageType,
logEvents
)

implicit val decoder: Decoder[CloudWatchLogsDecodedData] =
Decoder.forProduct6(
"owner",
"logGroup",
"logStream",
"subscriptionFilters",
"messageType",
"logEvents"
)(CloudWatchLogsDecodedData.apply)

private final case class Impl(
owner: String,
logGroup: String,
logStream: String,
subscriptionFilters: List[String],
messageType: String,
logEvents: List[CloudWatchLogsLogEvent]
) extends CloudWatchLogsDecodedData {
override def productPrefix = "CloudWatchLogsDecodedData"
}
}

sealed abstract class CloudWatchLogsLogEvent {
def id: String
def timestamp: Long
def message: String
def extractedFields: Option[Map[String, String]]
}

object CloudWatchLogsLogEvent {

def apply(
id: String,
timestamp: Long,
message: String,
extractedFields: Option[Map[String, String]]
): CloudWatchLogsLogEvent =
new Impl(id, timestamp, message, extractedFields)

private[events] implicit val decoder: Decoder[CloudWatchLogsLogEvent] =
Decoder.forProduct4("id", "timestamp", "message", "extractedFields")(
CloudWatchLogsLogEvent.apply
)

private final case class Impl(
id: String,
timestamp: Long,
message: String,
extractedFields: Option[Map[String, String]]
) extends CloudWatchLogsLogEvent {
override def productPrefix = "CloudWatchLogsLogEvent"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* 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.events

import io.circe.Decoder

import scala.util.Try

// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/aws-lambda/trigger/secretsmanager.d.ts
// https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets-lambda-function-overview.html

sealed abstract class SecretsManagerRotationEventStep

object SecretsManagerRotationEventStep {

case object CreateSecret extends SecretsManagerRotationEventStep
case object SetSecret extends SecretsManagerRotationEventStep
case object TestSecret extends SecretsManagerRotationEventStep
case object FinishSecret extends SecretsManagerRotationEventStep

private[events] implicit val decoder: Decoder[SecretsManagerRotationEventStep] =
Decoder.decodeString.emapTry {
case "createSecret" => Try(CreateSecret)
case "setSecret" => Try(SetSecret)
case "testSecret" => Try(TestSecret)
case "finishSecret" => Try(FinishSecret)
case s => scala.util.Failure(new IllegalArgumentException(s"Unknown step: $s"))
}
}

sealed abstract class SecretsManagerRotationEvent {
def step: SecretsManagerRotationEventStep
def secretId: String
def clientRequestToken: String
}

object SecretsManagerRotationEvent {

def apply(
step: SecretsManagerRotationEventStep,
secretId: String,
clientRequestToken: String
): SecretsManagerRotationEvent =
new Impl(step, secretId, clientRequestToken)

private[events] implicit val decoder: Decoder[SecretsManagerRotationEvent] =
Decoder.instance(c =>
for {
step <- c.get[SecretsManagerRotationEventStep]("Step")
secretId <- c.get[String]("SecretId")
clientRequestToken <- c.get[String]("ClientRequestToken")
} yield SecretsManagerRotationEvent(step, secretId, clientRequestToken))

private final case class Impl(
step: SecretsManagerRotationEventStep,
secretId: String,
clientRequestToken: String
) extends SecretsManagerRotationEvent {
override def productPrefix = "SecretsManagerRotationEvent"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* 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.events

import io.circe.literal._
import munit.FunSuite

class CloudWatchLogsEventSuite extends FunSuite {

test("decoder") {
assertEquals(event.as[CloudWatchLogsEvent].toTry.get, expected)
}

test("decoded data decoder") {
assertEquals(decodedDataJson.as[CloudWatchLogsDecodedData].toTry.get, expectedDecodedData)
}

def event = json"""
{
"awslogs": {
"data": "H4sIAAAAAAAA/6tWKkktLlGyUlAqSS0u0QHQKhZnJ2cm5+cXZOYnlQAAAP//"
}
}
"""

def expected =
CloudWatchLogsEvent(
awslogs = CloudWatchLogsEventData(
data = "H4sIAAAAAAAA/6tWKkktLlGyUlAqSS0u0QHQKhZnJ2cm5+cXZOYnlQAAAP//"
)
)

def decodedDataJson = json"""
{
"owner": "123456789012",
"logGroup": "/aws/lambda/my-function",
"logStream": "2024/01/15/[$$LATEST]abc123",
"subscriptionFilters": ["filter-1"],
"messageType": "DATA_MESSAGE",
"logEvents": [
{
"id": "event-id-1",
"timestamp": 1705312800000,
"message": "Log line one",
"extractedFields": { "field1": "value1" }
}
]
}
"""

def expectedDecodedData =
CloudWatchLogsDecodedData(
owner = "123456789012",
logGroup = "/aws/lambda/my-function",
logStream = "2024/01/15/[$LATEST]abc123",
subscriptionFilters = List("filter-1"),
messageType = "DATA_MESSAGE",
logEvents = List(
CloudWatchLogsLogEvent(
id = "event-id-1",
timestamp = 1705312800000L,
message = "Log line one",
extractedFields = Some(Map("field1" -> "value1"))
)
)
)
}
Loading
Loading