AWS.Logs reference
CreateLogStream
Section titled “CreateLogStream”Source:
src/AWS/Logs/CreateLogStream.ts
Runtime binding for logs:CreateLogStream.
Bind this operation to a LogGroup inside a function runtime to create
log streams dynamically (e.g. one stream per tenant or per day) before
writing to them with PutLogEvents, automatically injecting the log group
name. For a fixed stream known at deploy time, declare an
AWS.Logs.LogStream resource instead.
CreateLogStream: Writing Logs
Section titled “CreateLogStream: Writing Logs”const createLogStream = yield* AWS.Logs.CreateLogStream(logGroup);const putLogEvents = yield* AWS.Logs.PutLogEvents(logGroup);
yield* createLogStream({ logStreamName: `tenant-${tenantId}` }).pipe( Effect.catchTag("ResourceAlreadyExistsException", () => Effect.void),);yield* putLogEvents({ logStreamName: `tenant-${tenantId}`, logEvents: [{ timestamp, message }],});DeleteLogStream
Section titled “DeleteLogStream”Source:
src/AWS/Logs/DeleteLogStream.ts
Runtime binding for logs:DeleteLogStream.
Bind this operation to a LogGroup inside a function runtime to delete
dynamically-created log streams (e.g. cleaning up per-tenant streams
created with CreateLogStream), automatically injecting the log group
name.
DeleteLogStream: Writing Logs
Section titled “DeleteLogStream: Writing Logs”const deleteLogStream = yield* AWS.Logs.DeleteLogStream(logGroup);
yield* deleteLogStream({ logStreamName: `tenant-${tenantId}` }).pipe( Effect.catchTag("ResourceNotFoundException", () => Effect.void),);DescribeLogStreams
Section titled “DescribeLogStreams”Source:
src/AWS/Logs/DescribeLogStreams.ts
Runtime binding for logs:DescribeLogStreams.
Bind this operation to a LogGroup inside a function runtime to list the
streams of the group (e.g. to discover the most recently written stream
before reading with GetLogEvents), automatically injecting the log group
name.
DescribeLogStreams: Reading Logs
Section titled “DescribeLogStreams: Reading Logs”const describeLogStreams = yield* AWS.Logs.DescribeLogStreams(logGroup);
const { logStreams } = yield* describeLogStreams({ orderBy: "LastEventTime", descending: true, limit: 1,});Destination
Section titled “Destination”Source:
src/AWS/Logs/Destination.ts
A CloudWatch Logs destination — a cross-account subscription target that
forwards log events to a Kinesis stream. Producers in other accounts create
subscription filters whose destinationArn points at this destination;
the accessPolicy controls which accounts may subscribe.
Destination: Cross-Account Log Fan-Out
Section titled “Destination: Cross-Account Log Fan-Out”const destination = yield* Destination("CentralLogs", { targetArn: stream.streamArn, roleArn: role.roleArn, accessPolicy: { Version: "2012-10-17", Statement: [ { Effect: "Allow", Principal: { AWS: "123456789012" }, Action: ["logs:PutSubscriptionFilter"], Resource: "*", }, ], },});FilterLogEvents
Section titled “FilterLogEvents”Source:
src/AWS/Logs/FilterLogEvents.ts
Runtime binding for logs:FilterLogEvents.
Bind this operation to a LogGroup inside a function runtime to get a
callable that searches log events across all streams of the group,
automatically injecting the log group name.
FilterLogEvents: Reading Logs
Section titled “FilterLogEvents: Reading Logs”Search for a Marker
const filterLogEvents = yield* AWS.Logs.FilterLogEvents(logGroup);
const response = yield* filterLogEvents({ filterPattern: '"ERROR"', limit: 100,});Wire into a Lambda Function
// Provide the FilterLogEventsHttp layer on the Function's init Effect.export default SearchFunction.make( { main: import.meta.url, functionUrl: true }, Effect.gen(function* () { const logGroup = yield* AWS.Logs.LogGroup("AppLogs", {}); const filterLogEvents = yield* AWS.Logs.FilterLogEvents(logGroup); return { fetch: Effect.gen(function* () { const response = yield* filterLogEvents({ filterPattern: '"ERROR"' }); return HttpServerResponse.json({ events: response.events }); }), }; }).pipe(Effect.provide(AWS.Logs.FilterLogEventsHttp)),);GetLogEvents
Section titled “GetLogEvents”Source:
src/AWS/Logs/GetLogEvents.ts
Runtime binding for logs:GetLogEvents.
Bind this operation to a LogGroup inside a function runtime to get a
callable that reads log events from a single stream of the group,
automatically injecting the log group name.
GetLogEvents: Reading Logs
Section titled “GetLogEvents: Reading Logs”Read a Stream from the Beginning
const getLogEvents = yield* AWS.Logs.GetLogEvents(logGroup);
const response = yield* getLogEvents({ logStreamName: "my-stream", startFromHead: true,});Wire into a Lambda Function
// Provide the GetLogEventsHttp layer on the Function's init Effect;// combine with Layer.mergeAll when using several Logs bindings.export default TailFunction.make( { main: import.meta.url, functionUrl: true }, Effect.gen(function* () { const logGroup = yield* AWS.Logs.LogGroup("AppLogs", {}); const getLogEvents = yield* AWS.Logs.GetLogEvents(logGroup); return { fetch: Effect.gen(function* () { const { events } = yield* getLogEvents({ logStreamName: "my-stream", startFromHead: true, }); return HttpServerResponse.json({ events }); }), }; }).pipe(Effect.provide(AWS.Logs.GetLogEventsHttp)),);GetLogGroupFields
Section titled “GetLogGroupFields”Source:
src/AWS/Logs/GetLogGroupFields.ts
Runtime binding for logs:GetLogGroupFields (CloudWatch Logs Insights).
Bind this operation to a LogGroup inside a function runtime to discover
the fields present in the group’s recent log events (and the percentage of
events each field appears in), automatically injecting the log group name.
Useful for building Insights queries dynamically.
GetLogGroupFields: Logs Insights
Section titled “GetLogGroupFields: Logs Insights”const getLogGroupFields = yield* AWS.Logs.GetLogGroupFields(logGroup);
const { logGroupFields } = yield* getLogGroupFields();// e.g. [{ name: "@timestamp", percent: 100 }, { name: "@message", ... }]GetLogRecord
Section titled “GetLogRecord”Source:
src/AWS/Logs/GetLogRecord.ts
Runtime binding for logs:GetLogRecord (CloudWatch Logs Insights).
Bind this operation to the LogGroup an Insights query ran against to
fetch the complete log record behind a query-result row: every row returned
by GetQueryResults carries a @ptr
field that identifies the record.
GetLogRecord: Logs Insights
Section titled “GetLogRecord: Logs Insights”const getLogRecord = yield* AWS.Logs.GetLogRecord(logGroup);
const ptr = row.find((field) => field.field === "@ptr")?.value;const { logRecord } = yield* getLogRecord({ logRecordPointer: ptr! });// logRecord["@message"] is the full unparsed log lineGetQueryResults
Section titled “GetQueryResults”Source:
src/AWS/Logs/GetQueryResults.ts
Runtime binding for logs:GetQueryResults (CloudWatch Logs Insights).
Bind this operation to the LogGroup an Insights query was started against
(via StartQuery) to poll for its results.
GetQueryResults: Logs Insights
Section titled “GetQueryResults: Logs Insights”Poll Query Results
const getQueryResults = yield* AWS.Logs.GetQueryResults(logGroup);
const response = yield* getQueryResults({ queryId });if (response.status === "Complete") { // response.results is an array of field/value rows}Poll Until Complete
// Bounded, declarative polling — never a while-loop.const results = yield* getQueryResults({ queryId }).pipe( Effect.repeat({ schedule: Schedule.spaced("2 seconds"), until: (r) => r.status === "Complete", times: 15, }),);Wire into a Lambda Function
// Provide the layer on the Function's init Effect, merged with// StartQueryHttp since the two bindings are always used together.export default InsightsFunction.make( { main: import.meta.url, functionUrl: true }, Effect.gen(function* () { const logGroup = yield* AWS.Logs.LogGroup("AppLogs", {}); const startQuery = yield* AWS.Logs.StartQuery(logGroup); const getQueryResults = yield* AWS.Logs.GetQueryResults(logGroup); // ... start the query and poll for results in the fetch handler return { fetch: handler }; }).pipe( Effect.provide( Layer.mergeAll(AWS.Logs.StartQueryHttp, AWS.Logs.GetQueryResultsHttp), ), ),);LogEventSink
Section titled “LogEventSink”Source:
src/AWS/Logs/LogEventSink.ts
A batching sink over CloudWatch Logs PutLogEvents (10,000 events /
1,048,576 bytes per call, where each event costs its UTF-8 message size
plus 26 bytes of overhead).
Each input element is a raw InputLogEvent, so ordering stays with the
caller: PutLogEvents requires events in chronological order by
timestamp, and the time span within one batch must not exceed 24 hours.
Events the API reports via rejectedLogEventsInfo (older than 14 days or
the group’s retention period, expired, or more than 2 hours in the future)
are permanently rejected — they are dropped and surfaced with a
warning, never retried. The remaining valid events in the batch are still
ingested by the API.
LogEventSink: Streaming Log Events
Section titled “LogEventSink: Streaming Log Events”Drain a Stream of Events into a Log Stream
const sink = yield* AWS.Logs.LogEventSink(logGroup, { logStreamName: "audit-stream",});
// Inside a handler: drain fully before returning.yield* Stream.fromIterable(entries).pipe( Stream.map((entry) => ({ timestamp: entry.at, message: entry.text })), Stream.run(sink),);Wire into a Lambda Function
// LogEventSinkHttp batches over the PutLogEvents binding, so provide// PutLogEventsHttp into it with Layer.provideMerge.export default IngestFunction.make( { main: import.meta.url, functionUrl: true }, Effect.gen(function* () { const logGroup = yield* AWS.Logs.LogGroup("IngestLogs", {}); yield* AWS.Logs.LogStream("IngestStream", { logGroupName: logGroup.logGroupName, logStreamName: "ingest-stream", }); const sink = yield* AWS.Logs.LogEventSink(logGroup, { logStreamName: "ingest-stream", }); // ... run streams of InputLogEvents into `sink` in the fetch handler return { fetch: handler }; }).pipe( Effect.provide( Layer.provideMerge(AWS.Logs.LogEventSinkHttp, AWS.Logs.PutLogEventsHttp), ), ),);LogGroup
Section titled “LogGroup”Source:
src/AWS/Logs/LogGroup.ts
A CloudWatch Logs log group — the container for log streams and the unit that retention, encryption, metric filters, and subscriptions attach to.
LogGroup: Creating Log Groups
Section titled “LogGroup: Creating Log Groups”ECS Task Log Group
const logs = yield* LogGroup("TaskLogs", { retention: "7 days",});Encrypted Log Group with Deletion Protection
const key = yield* AWS.KMS.Key("LogsKey");const logs = yield* LogGroup("AuditLogs", { retention: "30 days", kmsKeyId: key.keyArn, deletionProtectionEnabled: true,});LogGroup: Writing Custom Log Events
Section titled “LogGroup: Writing Custom Log Events”Declare a LogStream and use the PutLogEvents binding inside a Lambda
function (or the batching LogEventSink for high-volume streams).
// initconst logGroup = yield* AWS.Logs.LogGroup("AuditLogs", { retention: "30 days",});const stream = yield* AWS.Logs.LogStream("AuditStream", { logGroupName: logGroup.logGroupName, logStreamName: "audit",});const putLogEvents = yield* AWS.Logs.PutLogEvents(logGroup);
// runtimeyield* putLogEvents({ logStreamName: "audit", logEvents: [{ timestamp, message: "user.login id=123" }],});LogGroup: Consuming Log Events
Section titled “LogGroup: Consuming Log Events”// Subscribe a Lambda handler to matching events (creates the// subscription filter + invoke permission automatically).yield* AWS.Logs.consumeLogEvents( logGroup, { filterPattern: "?ERROR ?Error" }, (events) => Stream.runForEach(events, (event) => Effect.log(`${event.logStream}: ${event.message}`), ),);LogGroup: Metrics
Section titled “LogGroup: Metrics”yield* AWS.Logs.MetricFilter("ErrorCount", { logGroupName: logGroup.logGroupName, filterPattern: '"ERROR"', metricTransformations: [{ metricName: "ErrorCount", metricNamespace: "MyApp", metricValue: "1", }],});LogStream
Section titled “LogStream”Source:
src/AWS/Logs/LogStream.ts
A CloudWatch Logs log stream — a sequence of log events within a log group.
Most log streams are created automatically by the emitting service (Lambda
creates its own streams under /aws/lambda/...); declare one explicitly
only when writing custom log events via putLogEvents.
LogStream: Creating Log Streams
Section titled “LogStream: Creating Log Streams”const stream = yield* LogStream("AuditStream", { logGroupName: logGroup.logGroupName,});MetricFilter
Section titled “MetricFilter”Source:
src/AWS/Logs/MetricFilter.ts
A CloudWatch Logs metric filter — extracts CloudWatch metrics from log events matching a filter pattern.
MetricFilter: Extracting Metrics
Section titled “MetricFilter: Extracting Metrics”Count Error Log Lines
const errors = yield* MetricFilter("ErrorCount", { logGroupName: logGroup.logGroupName, filterPattern: "?ERROR ?Error", metricTransformations: [ { metricName: "ErrorCount", metricNamespace: "MyApp", metricValue: "1", defaultValue: 0, }, ],});Extract a Latency Value from JSON Logs
const latency = yield* MetricFilter("RequestLatency", { logGroupName: logGroup.logGroupName, filterPattern: "{ $.latencyMs = * }", metricTransformations: [ { metricName: "LatencyMs", metricNamespace: "MyApp", metricValue: "$.latencyMs", unit: "Milliseconds", }, ],});PutLogEvents
Section titled “PutLogEvents”Source:
src/AWS/Logs/PutLogEvents.ts
Runtime binding for logs:PutLogEvents.
Bind this operation to a LogGroup inside a function runtime to get a
callable that writes log events to a stream of the group (e.g. custom audit
trails), automatically injecting the log group name. The target log stream
must already exist (declare an AWS.Logs.LogStream). Sequence tokens are no
longer required by CloudWatch Logs.
PutLogEvents: Writing Logs
Section titled “PutLogEvents: Writing Logs”Write an Audit Event
const putLogEvents = yield* AWS.Logs.PutLogEvents(logGroup);
yield* putLogEvents({ logStreamName: stream.logStreamName, logEvents: [{ timestamp: now, message: "user.login id=123" }],});Wire into a Lambda Function
// Bind in the init phase, call in the handler, and provide the// PutLogEventsHttp layer on the Function's init Effect.export default AuditFunction.make( { main: import.meta.url, functionUrl: true }, Effect.gen(function* () { const logGroup = yield* AWS.Logs.LogGroup("AuditLogs", { retention: "30 days", }); const stream = yield* AWS.Logs.LogStream("AuditStream", { logGroupName: logGroup.logGroupName, }); const putLogEvents = yield* AWS.Logs.PutLogEvents(logGroup); const LogStreamName = yield* stream.logStreamName;
return { fetch: Effect.gen(function* () { const timestamp = yield* Clock.currentTimeMillis; yield* putLogEvents({ logStreamName: yield* LogStreamName, logEvents: [{ timestamp, message: "audit.event" }], }); return HttpServerResponse.text("ok"); }), }; }).pipe(Effect.provide(AWS.Logs.PutLogEventsHttp)),);ResourcePolicy
Section titled “ResourcePolicy”Source:
src/AWS/Logs/ResourcePolicy.ts
An account-scoped CloudWatch Logs resource policy — grants AWS service principals (Route 53 query logging, API Gateway execution logs, OpenSearch slow logs, …) permission to deliver logs into your account.
AWS allows at most 10 resource policies per region per account and the
quota cannot be raised. Always use a deterministic policyName and destroy
policies you no longer need.
ResourcePolicy: Granting Log Delivery
Section titled “ResourcePolicy: Granting Log Delivery”const policy = yield* ResourcePolicy("Route53QueryLogging", { policyName: "route53-query-logging", policyDocument: { Version: "2012-10-17", Statement: [ { Effect: "Allow", Principal: { Service: "route53.amazonaws.com" }, Action: ["logs:CreateLogStream", "logs:PutLogEvents"], Resource: `arn:aws:logs:us-east-1:${accountId}:log-group:/aws/route53/*`, }, ], },});StartQuery
Section titled “StartQuery”Source:
src/AWS/Logs/StartQuery.ts
Runtime binding for logs:StartQuery (CloudWatch Logs Insights).
Bind this operation to a LogGroup inside a function runtime to get a
callable that starts an Insights query scoped to the group, automatically
injecting the log group name. Pair with
GetQueryResults to poll for results.
StartQuery: Logs Insights
Section titled “StartQuery: Logs Insights”Start an Insights Query
const startQuery = yield* AWS.Logs.StartQuery(logGroup);
const { queryId } = yield* startQuery({ queryString: "fields @timestamp, @message | limit 10", startTime: startEpochSeconds, endTime: endEpochSeconds,});Wire into a Lambda Function
// Insights queries are asynchronous: start one, then poll with the// GetQueryResults binding. Provide both HTTP layers with Layer.mergeAll.export default InsightsFunction.make( { main: import.meta.url, functionUrl: true }, Effect.gen(function* () { const logGroup = yield* AWS.Logs.LogGroup("AppLogs", {}); const startQuery = yield* AWS.Logs.StartQuery(logGroup); const getQueryResults = yield* AWS.Logs.GetQueryResults(logGroup); return { fetch: Effect.gen(function* () { const now = yield* Clock.currentTimeMillis; const { queryId } = yield* startQuery({ queryString: "fields @timestamp, @message | limit 10", startTime: Math.floor(now / 1000) - 3600, endTime: Math.floor(now / 1000), }); return HttpServerResponse.json({ queryId }); }), }; }).pipe( Effect.provide( Layer.mergeAll(AWS.Logs.StartQueryHttp, AWS.Logs.GetQueryResultsHttp), ), ),);StopQuery
Section titled “StopQuery”Source:
src/AWS/Logs/StopQuery.ts
Runtime binding for logs:StopQuery (CloudWatch Logs Insights).
Bind this operation to the LogGroup an Insights query was started against
(via StartQuery) to cancel it while it is
still Scheduled or Running — e.g. on caller timeout or shutdown.
StopQuery: Logs Insights
Section titled “StopQuery: Logs Insights”const startQuery = yield* AWS.Logs.StartQuery(logGroup);const stopQuery = yield* AWS.Logs.StopQuery(logGroup);
const { queryId } = yield* startQuery({ queryString, startTime, endTime });const { success } = yield* stopQuery({ queryId: queryId! });SubscriptionFilter
Section titled “SubscriptionFilter”Source:
src/AWS/Logs/SubscriptionFilter.ts
A CloudWatch Logs subscription filter — fans matching log events out of a log group to a Lambda function, Kinesis stream, Firehose delivery stream, or cross-account logs destination. A log group supports at most two subscription filters.
For the Lambda-consumer DX (subscribe a Lambda to a log group with automatic
permission wiring and payload decoding), prefer
consumeLogEvents.
SubscriptionFilter: Subscribing a Lambda Function
Section titled “SubscriptionFilter: Subscribing a Lambda Function”const filter = yield* SubscriptionFilter("ErrorFanout", { logGroupName: logGroup.logGroupName, filterPattern: "?ERROR ?Error", destinationArn: fn.functionArn,});SubscriptionFilter: Subscribing a Kinesis Stream
Section titled “SubscriptionFilter: Subscribing a Kinesis Stream”const filter = yield* SubscriptionFilter("StreamFanout", { logGroupName: logGroup.logGroupName, filterPattern: "", destinationArn: stream.streamArn, roleArn: role.roleArn, distribution: "ByLogStream",});