CloudWatch

Struct CloudWatch 

Source
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

  1. Producer (log): Receives Message objects, timestamps them, and pushes them into an internal MPSC (Multi-Producer, Single-Consumer) channel.
  2. Consumer (worker): A dedicated background thread that drains the channel using a greedy-drain strategy, batching logs to optimize network throughput to AWS.
  3. Service Layer: Handles the actual communication with the CloudWatch API via the internal Tokio runtime.

§Performance & Thread Safety

  • Non-blocking: The log method is essentially non-blocking, as it only performs a channel send operation.
  • Graceful Shutdown: Implements Drop to 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 stdout is 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

FeatureSDK Logger (CloudWatch)Stdout Logger (CloudWatchCout)
TransportHTTPS (AWS SDK)Standard Output (stdout)
Binary SizeLarger (SDK + TLS)Minimal (No AWS dependencies)
IAM ConfigHandled in-appHandled by Execution Environment
Best ForOn-premise, EC2, LegacyLambda, 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

Source

pub fn new(config: CloudWatchConfig) -> Box<CloudWatch>

Source

pub fn new_formatted<F>( config: CloudWatchConfig, formatter: F, ) -> Box<CloudWatch>
where F: MessageFormatter + Send + Sync + 'static,

Source

pub fn from_env<S>(log_group: S) -> Box<CloudWatch>
where S: Into<String>,

Source

pub fn from_env_formatted<S, F>(log_group: S, formatter: F) -> Box<CloudWatch>
where S: Into<String>, F: MessageFormatter + Send + Sync + 'static,

Source

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.

When the CloudwatchLogger goes out of scope, the following sequence occurs:

  1. Channel Closure: The sender is dropped (None). This signals the background worker that no more messages will be sent.
  2. Worker Drain: The worker’s receiver.recv() will return an error once the channel is empty, allowing its loop to terminate naturally.
  3. 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§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl LoggerImpl for CloudWatch

Source§

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
Source§

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:

  1. Timestamping: Uses a timestamp generated at the log moment.
  2. 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.
Source§

fn as_any(&self) -> &dyn Any

Returns a reference to the underlying type as Any for downcasting.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
§

impl<Unshared, Shared> IntoShared<Shared> for Unshared
where Shared: FromUnshared<Unshared>,

§

fn into_shared(self) -> Shared

Creates a shared type from an unshared type.
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more