pub struct CloudWatch { /* private fields */ }Expand description
A high-level, thread-safe logger implementation for AWS CloudWatch.
This structure acts as a bridge between the application’s logging calls and the asynchronous AWS SDK. It implements a producer-consumer pattern using a dedicated background worker thread to ensure that logging operations do not block the main application execution.
§Architecture
- Producer (
log): ReceivesMessageobjects, timestamps them, and pushes them into an internal MPSC (Multi-Producer, Single-Consumer) channel. - Consumer (
worker): A dedicated background thread that drains the channel using a greedy-drain strategy, batching logs to optimize network throughput to AWS. - Service Layer: Handles the actual communication with the CloudWatch API via the internal Tokio runtime.
§Performance & Thread Safety
- Non-blocking: The
logmethod is essentially non-blocking, as it only performs a channel send operation. - Graceful Shutdown: Implements
Dropto ensure that the channel is closed and all pending logs are flushed to AWS before the thread joins and the application terminates.
§Alternative: CloudWatch via Standard Output (Cout)
While this CloudWatch implementation provides a robust, SDK-based integration
with the AWS API, many modern AWS environments are optimized for “Log Driver”
ingestion.
If your application runs in AWS Lambda, ECS (with the awslogs driver),
or Fargate, you may prefer using the CloudWatchCout service.
§Why use the Cout Alternative?
- Performance: Writing to
stdoutis significantly faster than performing HTTPS requests, even with background workers. It avoids the CPU and memory overhead of the AWS SDK and TLS stack. - Security: You do not need to provide AWS IAM credentials (like Access Keys) to your application code. The execution environment (e.g., the Lambda Role) automatically handles the permissions for the captured stream.
- Resilience: If the network is unstable, logs are buffered by the container runtime or orchestrator rather than occupying your application’s heap memory.
§Comparison
| Feature | SDK Logger (CloudWatch) | Stdout Logger (CloudWatchCout) |
|---|---|---|
| Transport | HTTPS (AWS SDK) | Standard Output (stdout) |
| Binary Size | Larger (SDK + TLS) | Minimal (No AWS dependencies) |
| IAM Config | Handled in-app | Handled by Execution Environment |
| Best For | On-premise, EC2, Legacy | Lambda, ECS, Fargate, Kubernetes |
§Usage
You can quickly initialize the alternative via the factory:
use timber_rust::LoggerFactory;
use timber_rust::Concurrency;
// Direct (Sync) for Lambda
let logger = LoggerFactory::cloudwatch().cout().build(Concurrency::Sync);
// Queued (Async) for ECS/Fargate
let logger = LoggerFactory::cloudwatch().cout().build(Concurrency::Async);See also: CloudWatchCoutMessageFormatter
for the JSON schema used by the alternative.
§Example
use timber_rust::Logger;
use timber_rust::logger::CloudWatch;
use timber_rust::service::aws::Config;
let config = Config::new("access", "secret", "my-group", "us-east-1");
let logger = CloudWatch::new(config);
let logger = Logger::new(logger);Implementations§
Source§impl CloudWatch
impl CloudWatch
pub fn new(config: CloudWatchConfig) -> Box<CloudWatch>
pub fn new_formatted<F>( config: CloudWatchConfig, formatter: F, ) -> Box<CloudWatch>
pub fn from_env<S>(log_group: S) -> Box<CloudWatch>
pub fn from_env_formatted<S, F>(log_group: S, formatter: F) -> Box<CloudWatch>
pub fn with_service( service: Box<dyn CloudWatchService + Send + Sync>, ) -> Box<CloudWatch>
Trait Implementations§
Source§impl Drop for CloudWatch
Ensures a graceful shutdown of the logging pipeline.
impl Drop for CloudWatch
Ensures a graceful shutdown of the logging pipeline.
When the CloudwatchLogger goes out of scope, the following sequence occurs:
- Channel Closure: The
senderis dropped (None). This signals the background worker that no more messages will be sent. - Worker Drain: The worker’s
receiver.recv()will return an error once the channel is empty, allowing its loop to terminate naturally. - Thread Join: The main thread blocks until the worker thread has finished processing and sending the final batch of logs.
This mechanism prevents data loss during application shutdown or restarts.
Source§impl LoggerImpl for CloudWatch
impl LoggerImpl for CloudWatch
Source§fn status(&self) -> LoggerStatus
fn status(&self) -> LoggerStatus
Returns the current operational status of the Loki service.
This method performs a live health check by hitting the /loki/status endpoint.
It uses a functional pipeline to transform the network result into a LoggerStatus.
§Performance Note:
This call is blocking. If the network is slow or the Loki server is hanging, this method will block the calling thread until the default timeout is reached.
§Returns
LoggerStatus::Running- Server is reachable and returned a success code.LoggerStatus::Broken- Any failure occurred (DNS, Connection Refused, 404, 500, etc.).
Source§fn log(&self, message: Message)
fn log(&self, message: Message)
Enqueues a Message for asynchronous processing and delivery.
This is the primary entry point for recording logs. It performs two critical tasks:
- Timestamping: Uses a timestamp generated at the log moment.
- Asynchronous Dispatch: Sends the message through an MPSC channel to the background worker.
§Thread Safety & Performance
This method is non-blocking (except for a very brief lock on the highwater
timestamp). If the background worker is overloaded or the channel is
disconnected, it triggers the Fallback immediately to avoid data loss.
§Parameters
message: The log entry containing level, target, and content.
Auto Trait Implementations§
impl Freeze for CloudWatch
impl !RefUnwindSafe for CloudWatch
impl Send for CloudWatch
impl Sync for CloudWatch
impl Unpin for CloudWatch
impl !UnwindSafe for CloudWatch
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more