CloudWatch client
AmplifyCloudWatchClient is a standalone client for sending application logs to Amazon CloudWatch Logs. It provides:
- Local persistence for offline support
- Automatic batching and interval-based flushing (default: every 60 seconds)
- Integration with Amplify logging as a log sink
- Per-namespace and per-user log level constraints
- Enable/disable toggle that silently drops new logs while preserving cached ones
Getting started
Installation
Add the dependency to your module's build.gradle.kts:
dependencies { implementation("com.amplifyframework:aws-cloudwatch:ANDROID_VERSION")}Initialize the client
The logGroupName is required. It must match a CloudWatch log group your app has permission to write to.
import com.amplifyframework.cloudwatch.AmplifyCloudWatchClientimport com.amplifyframework.cloudwatch.AmplifyCloudWatchClientOptions
val cloudWatch = AmplifyCloudWatchClient( context = applicationContext, region = "us-east-1", credentialsProvider = credentialsProvider, options = AmplifyCloudWatchClientOptions { logGroupName = "/app/my-android-app" })Configuration options
You can customize the client behavior through the options object:
| Option | Default | Description |
|---|---|---|
logGroupName | (required) | The CloudWatch log group logs are sent to. |
localStoreMaxSizeInMB | 5 | Maximum size of the local log cache in MB. |
flushStrategy | FlushStrategy.Interval() (60s) | Automatic flush interval. Use FlushStrategy.None for manual-only flushing. |
loggingConstraints | LoggingConstraints() | Per-namespace and per-user log level rules. |
configureClient | null | Escape hatch to customize the underlying AWS SDK CloudWatchLogsClient. |
import com.amplifyframework.cloudwatch.AmplifyCloudWatchClientOptionsimport com.amplifyframework.cloudwatch.FlushStrategyimport com.amplifyframework.cloudwatch.LoggingConstraintsimport com.amplifyframework.logging.LogLevelimport kotlin.time.Duration.Companion.seconds
val options = AmplifyCloudWatchClientOptions { logGroupName = "/app/my-android-app" localStoreMaxSizeInMB = 10 flushStrategy = FlushStrategy.Interval(30.seconds) loggingConstraints = LoggingConstraints(defaultLogLevel = LogLevel.Verbose) configureClient { retryStrategy { maxAttempts = 10 } }}To disable automatic flushing:
options = AmplifyCloudWatchClientOptions { logGroupName = "/app/my-android-app" flushStrategy = FlushStrategy.None}Usage
Register as a logging sink
The client implements AmplifyFoundation's LogSink interface. Register it once to capture every message logged through Amplify logging:
import com.amplifyframework.logging.AmplifyLogging
AmplifyLogging.addSink(cloudWatch)Emit a message directly
You can also send a log message to the client without going through Amplify logging:
import com.amplifyframework.logging.LogLevelimport com.amplifyframework.logging.LogMessage
cloudWatch.emit(LogMessage(LogLevel.Error, "MyNamespace", "Something went wrong", null))Messages emitted while the client is disabled are silently dropped.
Flush logs
The client automatically flushes cached logs at the configured interval (default: 60 seconds). You can also trigger a manual flush:
when (val result = cloudWatch.flushLogs()) { is Result.Success -> println("Flushed: ${result.data.flushed}") is Result.Failure -> println("Flush error: ${result.error}")}Manual flushes work even when the client is disabled, allowing you to drain cached logs without re-enabling collection.
Enable and disable
You can toggle log collection and automatic flushing at runtime. When disabled, new logs are silently dropped but already-cached logs remain in storage.
cloudWatch.disable()// Logs are dropped, auto-flush paused
cloudWatch.enable()// Collection and auto-flush resumeSet the user identifier
Associate cached and future logs with a user identifier, for example after sign-in.
Pass null to clear it on sign-out.
cloudWatch.setUserIdentifier("user-123")Set logging constraints
Update the log level rules at runtime, for example after fetching remote configuration:
import com.amplifyframework.cloudwatch.LoggingConstraintsimport com.amplifyframework.logging.LogLevel
cloudWatch.setLoggingConstraints( LoggingConstraints( defaultLogLevel = LogLevel.Warn, namespaceLogLevel = mapOf("Storage" to LogLevel.Debug) ))Observe events
The client surfaces write and flush failures through an events stream so you can react to persistent problems:
import com.amplifyframework.cloudwatch.LoggingEventimport kotlinx.coroutines.flow.collect
cloudWatch.events.collect { event -> when (event) { is LoggingEvent.WriteLogFailure -> { /* handle write failure */ } is LoggingEvent.FlushLogFailure -> { /* handle flush failure */ } }}Advanced
Escape hatch
Access the underlying AWS SDK CloudWatchLogsClient for operations not covered by this client's API:
val sdkClient = cloudWatch.getCloudWatchLogsClient()// Use sdkClient for direct CloudWatch Logs API callsError handling
Operations surface errors through a sealed error hierarchy:
| Error type | Description |
|---|---|
AmplifyCloudWatchStorageException | Local storage error (file I/O, log rotation). |
AmplifyCloudWatchServiceException | A CloudWatch Logs API call failed. |
AmplifyCloudWatchConfigurationException | The client was misconfigured. |
AmplifyCloudWatchUnknownException | Unexpected or uncategorized error. |
flushLogs() returns Result<FlushData, AmplifyCloudWatchException>:
when (val result = cloudWatch.flushLogs()) { is Result.Success -> { /* success */ } is Result.Failure -> when (result.error) { is AmplifyCloudWatchStorageException -> { /* storage error */ } is AmplifyCloudWatchServiceException -> { /* service error */ } is AmplifyCloudWatchConfigurationException -> { /* misconfiguration */ } is AmplifyCloudWatchUnknownException -> { /* unexpected error */ } }}CloudWatch Logs service limits
The client batches logs to stay within the CloudWatch Logs PutLogEvents limits:
| Limit | Value |
|---|---|
| Max batch size | 1 MB |
| Max events per batch | 10,000 |
| Max single event size | 256 KB |