See https://github.com/RevenueCat/khepri/pull/6798.
This can help debug issues as it helps us cross-reference requests on
our end.
### Changes:
- Logging `X-Request-ID` and `X-Amzn-Trace-ID` headers if present (only
in verbose mode)
- Logging these even for failed requests
- Also logging `request_handled_by_load_shedder` for failed requests
- To accomplish that. `HTTPURLResponse` now conforms to our
`HTTPResponseType`, this allows us to extract headers in an uniform way
### Example:
```
[network] DEBUG: ℹ️ API request completed: GET '/v1/subscribers/$RCAnonymousID%3Ad9dc4f3b33054cf28c0f2ec9da0f48d5' (304)
Request-ID: 'be534c50-5231-403b-be2f-7c077861751d'; Amzn-Trace-ID: 'Root=1-6532c6ca-7ef80f961ec9c4145484df13'
```
Fixes SDK-3084

## Changes:
- Added new `ENABLE_CUSTOM_ENTITLEMENT_COMPUTATION` compile time flag
- Hidden `configureInCustomEntitlementsModeWithApiKey` behind
`ENABLE_CUSTOM_ENTITLEMENT_COMPUTATION`
- Added new `RevenueCat_CustomEntitlementComputation` SPM target and
library
- Added CircleCI job for `swift build --target
RevenueCat_CustomEntitlementComputation`
- Added new `SPMCustomEntitlementComputationInstallation` using the new
`configureInCustomEntitlementsComputationMode`
- Added CircleCI job for `SPMCustomEntitlementComputationInstallation`
- Added `FrameworkDisambiguation.swift` to avoid using `RevenueCat.`
disambiguation for files that
- Changed API testers to only use the new methods if
`ENABLE_CUSTOM_ENTITLEMENT_COMPUTATION` is defined
- Updated `DangerousSettings` to not expose
`customEntitlementComputation` publicly. The only way to use that now
with `public` API is through
`Purchases.configureInCustomEntitlementsModeWithApiKey`
- Updated sample app to use new library
Defining the property "twice" was a big weird and hard to read. Now
`logLevel` is only defined once, with the default value extracted into a
separate method.
We had this fragile pattern in several tests:
```swift
var loggedMessages = [String]()
let originalLogHandler = Logger.logHandler
defer { Logger.logHandler = originalLogHandler }
Logger.logHandler = { _, message, _, _, _ in
loggedMessages.append(message)
}
```
Which was too verbose and error prone.
This new type works like an RAII type. Its lifetime scopes the messages that are observed, so simply having a reference around for the lifetime of the test allows observing only those messages.
This much simpler abstraction will make it easier for us to test more of what's logged by the SDK.
### Examples:
- Initialize in `setUp`:
```swift
private var testLogHandler: TestLogHandler!
override func setUp() {
super.setUp()
self.testLogHandler = TestLogHandler()
}
override func tearDown() {
self.testLogHandler = nil
super.tearDown()
}
func testExample() {
// Run code
expect(self.testLogHandler.messages).to(contain(...))
}
```
- Alternatively, `TestLogHandler` can be used locally within a single test:
```swift
func testExample() {
let logHandler = TestLogHandler()
// Run some code
expect(logHandler.loggedMessages.onlyElement?.message) == "Expected log"
}
```
### Notes:
This implicitly overrides `Purchases.shared.verboseLogHandler` while running tests, but it just wraps it by still invoking the default handler, so logs are still printed in the console.
Follow up to #1489
Examples:
> 2022-04-11 14:36:08.815265-0700 UnitTestsHostApp[58688:3901390] [Purchases] - INFO: 😻💰 Purchased product - 'com.revenuecat.monthly_4.99.1_week_intro'
> 2022-04-11 14:37:31.793204-0700 BackendIntegrationTestsHostApp[58835:3904176] [Purchases] - ERROR: 💰 Product purchase for 'com.revenuecat.monthly_4.99.1_week_intro' failed with error: Error Domain=RevenueCat.ErrorCode Code=34 "The information associated with this PromotionalOffer is not valid.