Skip to content

feat(logging): add implementation for cloudwatch client#4212

Merged
harsh62 merged 6 commits into
feat/v3-cloudwatch-clientfrom
cloudwatch-client-3
May 8, 2026
Merged

feat(logging): add implementation for cloudwatch client#4212
harsh62 merged 6 commits into
feat/v3-cloudwatch-clientfrom
cloudwatch-client-3

Conversation

@thisisabhash
Copy link
Copy Markdown
Member

Issue #

NA

Description

Add implementation for cloudwatch logging client

General Checklist

  • Added new tests to cover change, if needed
  • Build succeeds with all target using Swift Package Manager
  • All unit tests pass
  • All integration tests pass
  • Security oriented best practices and standards are followed (e.g. using input sanitization, principle of least privilege, etc)
  • Documentation update for the change if required
  • PR title conforms to conventional commit style
  • New or updated tests include Given When Then inline code documentation and are named accordingly testThing_condition_expectation()
  • If breaking change, documentation/changelog update with migration instructions

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@thisisabhash thisisabhash requested a review from a team as a code owner May 5, 2026 21:12
@codecov
Copy link
Copy Markdown

codecov Bot commented May 5, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (cloudwatch-client-2@2f378fb). Learn more about missing BASE report.

Additional details and impacted files
@@                  Coverage Diff                   @@
##             cloudwatch-client-2    #4212   +/-   ##
======================================================
  Coverage                       ?   66.64%           
======================================================
  Files                          ?     1145           
  Lines                          ?    43602           
  Branches                       ?        0           
======================================================
  Hits                           ?    29057           
  Misses                         ?    14545           
  Partials                       ?        0           
Flag Coverage Δ
API_plugin_unit_test 68.39% <ø> (?)
AWSPluginsCore 68.48% <ø> (?)
Amplify 47.47% <ø> (?)
Amplify_Foundation_Bridge_unit_test 62.28% <ø> (?)
Amplify_Foundation_unit_test 67.64% <ø> (?)
Analytics_plugin_unit_test 83.43% <ø> (?)
Auth_plugin_unit_test 72.32% <ø> (?)
DataStore_plugin_unit_test 81.89% <ø> (?)
Firehose_plugin_unit_test 53.15% <ø> (?)
Geo_plugin_unit_test 73.39% <ø> (?)
Kinesis_plugin_unit_test 52.17% <ø> (?)
Logging_plugin_unit_test 57.88% <ø> (?)
Predictions_plugin_unit_test 33.89% <ø> (?)
PushNotifications_plugin_unit_test 85.66% <ø> (?)
RecordCache_unit_test 76.40% <ø> (?)
Storage_plugin_unit_test 78.67% <ø> (?)
unit_tests 66.64% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Base automatically changed from cloudwatch-client-2 to feat/v3-cloudwatch-client May 8, 2026 18:55
Comment on lines +12 to +44
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let rawString = try? container.decode(String.self).lowercased() {
switch rawString {
case "error": self = .error
case "warn": self = .warn
case "info": self = .info
case "debug": self = .debug
case "verbose": self = .verbose
case "none": self = .none
default:
let context = DecodingError.Context(
codingPath: [],
debugDescription: "No matching LogLevel found"
)
throw DecodingError.valueNotFound(AmplifyFoundation.LogLevel.self, context)
}
} else if let rawInt = try? container.decode(Int.self),
let value = AmplifyFoundation.LogLevel(rawValue: rawInt) {
self = value
} else {
let context = DecodingError.Context(
codingPath: [],
debugDescription: "Unable to decode LogLevel"
)
throw DecodingError.dataCorrupted(context)
}
}

public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(rawValue)
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious to understand why you had to write this custom encoding and decoding logic, shouldn't this be automatically taken care by Swift or we have to follow some custom logic?

Copy link
Copy Markdown
Member Author

@thisisabhash thisisabhash May 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Earlier this was being populated from config file, so this was needed for Codable conformance. Will remove it as it's not needed in the new client.

Comment on lines 31 to 32
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding default values here to ?

}

extension CloudWatchLoggingConsumer: LogBatchConsumer {
func consume(batch: any LogBatch) async throws {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems to be a long method, can we break it down to logical pieces and test them individually and also combined? Similar thing applies to some other methods in the file too.

self.logGroupName = logGroupName
}

private func safeEncode(_ value: some Encodable) throws -> Data {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is safeEncode reallly necessary? because I see encode without locks in other parts of the file.

func encode(entry: LogEntry) throws -> Data {
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .millisecondsSince1970
encoder.outputFormatting = .sortedKeys
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a requriement?


func decode(from fileURL: URL) throws -> [LogEntry] {
guard fileURL.isFileURL else {
throw DecodingError.invalidScheme(log: fileURL)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this error be more descriptive, like invalidPath or invalidFile, not sure why we chose invalid scheme.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's coming from here: isFileURL checks if file:// scheme is present
https://developer.apple.com/documentation/foundation/nsurl/isfileurl


// MARK: - LogSinkBehavior

public var id: String { sinkId }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we rename this to a sink id?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is coming from LogSinkBehavior conformance.

@harsh62 harsh62 merged commit 24829d8 into feat/v3-cloudwatch-client May 8, 2026
92 of 93 checks passed
@harsh62 harsh62 deleted the cloudwatch-client-3 branch May 8, 2026 19:18
thisisabhash added a commit that referenced this pull request May 8, 2026
* feat(logging): add v3 cloudwatch @SPI definitions

* add privacyinfo

* chore(logging): move shared code to internal module

* fix unit tests

* feat(logging): add implementation for cloudwatch client

---------

Co-authored-by: Harsh <6162866+harsh62@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants