Skip to content

Commit

Permalink
RCOCOA-2273: Add support for Logger categories/ Improve current logge…
Browse files Browse the repository at this point in the history
…r. (#8608)

Add support for Logger categories
  • Loading branch information
dianaafanador3 committed Jul 22, 2024
1 parent ae827ea commit e3351e3
Show file tree
Hide file tree
Showing 12 changed files with 917 additions and 135 deletions.
85 changes: 85 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,88 @@
x.y.z Release notes (yyyy-MM-dd)
=============================================================
### Enhancements
* Added support for filtering logs by category. Users wil have more fine grained control over
the log level for each category as well.
```swift
Logger.setLogLevel(.info, category: Category.Storage.transactions)
```

### Fixed
* <How to hit and notice issue? what was the impact?> ([#????](https://github.com/realm/realm-swift/issues/????), since v?.?.?)
* None.

### Deprecations
* `RLMLogger.level`/`Logger.level` has been deprecated in favor of using `RLMLogger.setLevel:forCategory:`/`Logger.setLevel(:category:)` and `RLMLogger.getLevelForCategory:`/`Logger.getLevel(for:)`.
* It is not recommended to initialize a `RLMLogger/Logger` with a level anymore.

### Compatibility
* Realm Studio: 15.0.0 or later.
* APIs are backwards compatible with all previous releases in the 10.x.y series.
* Carthage release for Swift is built with Xcode 15.4.0.
* CocoaPods: 1.10 or later.
* Xcode: 15.1.0-15.4.0.

### Internal
* Upgraded realm-core from ? to ?

10.52.2 Release notes (2024-07-19)
=============================================================

### Enhancements

* Server-side role and permissions changes no longer require a client reset to
update the local Realm. ([Core #7440](https://github.com/realm/realm-core/pull/7440))

### Fixed

* Deleting an object with a `List<AnyRealmValue` proeprty which linked to an
object which had been deleted by another sync client would switch to the
incorrect cascade mode and perform a cascading delete. This meant that if any
subsequent properties in the object linked to another top-level object and
that was the *only* link to that object, the target object would also be
recursively deleted as if it was an embedded object.
([Core #7828](https://github.com/realm/realm-core/issues/7828), since v10.51.0).
* Fix the assertion failure `array_backlink.cpp:112: Assertion failed:
int64_t(value >> 1) == key.value` when removing links to an object (either by
reassigning the link or by deleting the object). This could happen if the link
came from a collection inside a `AnyRealmValue`, any `Map`, or a
`List<AnyRealmValue>`, and there were more than 256 objects of the type which
contained the link.
([Core #7594](https://github.com/realm/realm-core/issues/7594), since v10.8.0)
* Fix the assertion failure `array.cpp:319: Array::move() Assertion failed:
begin <= end [2, 1]` when deleting objects containing collections nested
inside a `AnyRealmValue` when this caused bptree leaves to be merged.
()[Core #7839](https://github.com/realm/realm-core/issues/7839), since v10.51.0).
* `SyncSession.wait(for .upload)` was inconsistent in how it handled commits
which do no produce any changesets to upload (such as modifying flexible sync
subscriptions). Previously if all unuploaded commits had empty changesets and
the session had never completed a download it would wait for download
completion, and otherwise it would complete immediate. It now always
completes immediately. ([Core #7796](https://github.com/realm/realm-core/pull/7796)).
* The sync client could hit an assertion failure if a session is resumed while
the session is being suspended. ([Core #7860](https://github.com/realm/realm-core/issues/7860), since v10.27.0)
* If a sync session was interrupted by a disconnect or restart while downloading
a bootstrap (a set of downloads caused by adding or changing a query
subscription), stale data from the previous bootstrap could be included when
the session reconnected and completed downloading the bootstrap. This could
lead to objects stored in the database that do not match the actual state of
the server and potentially leading to compensating writes.
([Core #7827](https://github.com/realm/realm-core/issues/7827), since v10.27.0)
* Fixed unnecessary server roundtrips when there was no download to acknowledge
([Core #2129](https://jira.mongodb.org/browse/RCORE-2129), since v10.51.0).

### Compatibility

* Realm Studio: 15.0.0 or later.
* APIs are backwards compatible with all previous releases in the 10.x.y series.
* Carthage release for Swift is built with Xcode 15.4.0.
* CocoaPods: 1.10 or later.
* Xcode: 15.1.0-16 beta 3.

### Internal

* Upgraded realm-core from v14.10.2 to 14.11.0

10.52.1 Release notes (2024-06-28)
=============================================================

Expand Down
4 changes: 4 additions & 0 deletions Realm.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@
AC81360F287F21350029F15E /* AsymmetricObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC81360E287F21350029F15E /* AsymmetricObject.swift */; };
AC813612287F21700029F15E /* RLMAsymmetricObject.h in Headers */ = {isa = PBXBuildFile; fileRef = AC813610287F21700029F15E /* RLMAsymmetricObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
AC813613287F21700029F15E /* RLMAsymmetricObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC813611287F21700029F15E /* RLMAsymmetricObject.mm */; };
AC848BEC2BFFA4AF0026A2A6 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC848BEB2BFFA4AF0026A2A6 /* Logger.swift */; };
AC8846762686573B00DF4A65 /* SwiftUISyncTestHostApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC8846752686573B00DF4A65 /* SwiftUISyncTestHostApp.swift */; };
AC8846782686573B00DF4A65 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC8846772686573B00DF4A65 /* ContentView.swift */; };
AC8846B72687BC4100DF4A65 /* SwiftUIServerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC8846B62687BC4100DF4A65 /* SwiftUIServerTests.swift */; };
Expand Down Expand Up @@ -912,6 +913,7 @@
AC81360E287F21350029F15E /* AsymmetricObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsymmetricObject.swift; sourceTree = "<group>"; };
AC813610287F21700029F15E /* RLMAsymmetricObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RLMAsymmetricObject.h; sourceTree = "<group>"; };
AC813611287F21700029F15E /* RLMAsymmetricObject.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RLMAsymmetricObject.mm; sourceTree = "<group>"; };
AC848BEB2BFFA4AF0026A2A6 /* Logger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
AC8846732686573B00DF4A65 /* SwiftUISyncTestHost.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftUISyncTestHost.app; sourceTree = BUILT_PRODUCTS_DIR; };
AC8846752686573B00DF4A65 /* SwiftUISyncTestHostApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUISyncTestHostApp.swift; sourceTree = "<group>"; };
AC8846772686573B00DF4A65 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1362,6 +1364,7 @@
AC7825B82ACD90BE007ABA4B /* Geospatial.swift */,
5D1534B71CCFF545008976D7 /* LinkingObjects.swift */,
5D660FE41BE98D670021E04F /* List.swift */,
AC848BEB2BFFA4AF0026A2A6 /* Logger.swift */,
0C3BD4D225C1C5AB007CFDD3 /* Map.swift */,
5D660FE51BE98D670021E04F /* Migration.swift */,
CF76F80124816B3800890DD2 /* MongoClient.swift */,
Expand Down Expand Up @@ -2558,6 +2561,7 @@
3F857A482769291800F9B9B1 /* KeyPathStrings.swift in Sources */,
5D1534B81CCFF545008976D7 /* LinkingObjects.swift in Sources */,
5D660FF21BE98D670021E04F /* List.swift in Sources */,
AC848BEC2BFFA4AF0026A2A6 /* Logger.swift in Sources */,
0C3BD4D325C1C5AB007CFDD3 /* Map.swift in Sources */,
5D660FF31BE98D670021E04F /* Migration.swift in Sources */,
CF76F80224816B3800890DD2 /* MongoClient.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion Realm/ObjectServerTests/RLMSyncTestCase.mm
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ - (RLMApp *)appWithId:(NSString *)appId {
RLMApp *app = [RLMApp appWithConfiguration:config];
RLMSyncManager *syncManager = app.syncManager;
syncManager.userAgent = self.name;
RLMLogger.defaultLogger.level = RLMLogLevelWarn;
[RLMLogger setLevel:RLMLogLevelWarn forCategory:RLMLogCategorySync];
return app;
}

Expand Down
114 changes: 106 additions & 8 deletions Realm/RLMLogger.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,33 +48,95 @@ typedef RLM_CLOSED_ENUM(NSUInteger, RLMLogLevel) {
RLMLogLevelAll
} NS_SWIFT_NAME(LogLevel);

/**
An enum representing different categories of sync-related logging that can be configured.
Setting the log level for a parent category automatically sets the same level for all child categories.
Category hierarchy:
```
Realm
├─► Storage
│ ├─► Transaction
│ ├─► Query
│ ├─► Object
│ └─► Notification
├─► Sync
│ ├─► Client
│ │ ├─► Session
│ │ ├─► Changeset
│ │ ├─► Network
│ │ └─► Reset
│ └─► Server
├─► App
└─► Sdk
```
*/
typedef NS_ENUM(NSUInteger, RLMLogCategory) {
/// Top level log category for Realm, updating this category level would set all other subcategories too.
RLMLogCategoryRealm,
/// Log category for all sdk related logs.
RLMLogCategorySDK,
/// Log category for all app related logs.
RLMLogCategoryApp,
/// Log category for all database related logs.
RLMLogCategoryStorage,
/// Log category for all database transaction related logs.
RLMLogCategoryStorageTransaction,
/// Log category for all database queries related logs.
RLMLogCategoryStorageQuery,
/// Log category for all database object related logs.
RLMLogCategoryStorageObject,
/// Log category for all database notification related logs.
RLMLogCategoryStorageNotification,
/// Log category for all sync related logs.
RLMLogCategorySync,
/// Log category for all sync client related logs.
RLMLogCategorySyncClient,
/// Log category for all sync client session related logs.
RLMLogCategorySyncClientSession,
/// Log category for all sync client changeset related logs.
RLMLogCategorySyncClientChangeset,
/// Log category for all sync client network related logs.
RLMLogCategorySyncClientNetwork,
/// Log category for all sync client reset related logs.
RLMLogCategorySyncClientReset,
/// Log category for all sync server related logs.
RLMLogCategorySyncServer
};

/// A log callback function which can be set on RLMLogger.
///
/// The log function may be called from multiple threads simultaneously, and is
/// responsible for performing its own synchronization if any is required.
RLM_SWIFT_SENDABLE // invoked on a background thread
typedef void (^RLMLogFunction)(RLMLogLevel level, NSString *message);

/// A log callback function which can be set on RLMLogger.
///
/// The log function may be called from multiple threads simultaneously, and is
/// responsible for performing its own synchronization if any is required.
RLM_SWIFT_SENDABLE // invoked on a background thread
typedef void (^RLMLogCategoryFunction)(RLMLogLevel level, RLMLogCategory category, NSString *message) NS_REFINED_FOR_SWIFT;
/**
`RLMLogger` is used for creating your own custom logging logic.
Global logger class used by all Realm components.
You can define your own logger creating an instance of `RLMLogger` and define the log function which will be
invoked whenever there is a log message.
Set this custom logger as you default logger using `setDefaultLogger`.
RLMLogger.defaultLogger = [[RLMLogger alloc] initWithLevel:RLMLogLevelDebug
logFunction:^(RLMLogLevel level, NSString * message) {
NSLog(@"Realm Log - %lu, %@", (unsigned long)level, message);
RLMLogger.defaultLogger = [[RLMLogger alloc] initWithLogFunction:^(RLMLogLevel level, NSString *category, NSString *message) {
NSLog(@"Realm Log - %lu, %@, %@", (unsigned long)level, category, message);
}];
@note By default default log threshold level is `RLMLogLevelInfo`, and logging strings are output to Apple System Logger.
@note The default log threshold level is `RLMLogLevelInfo` for the log category `RLMLogCategoryRealm`,
and logging strings are output to Apple System Logger.
*/
@interface RLMLogger : NSObject

/**
Gets the logging threshold level used by the logger.
*/
@property (nonatomic) RLMLogLevel level;
@property (nonatomic) RLMLogLevel level
__attribute__((deprecated("Use `setLevel(level:category)` or `setLevel:category` instead.")));

/// :nodoc:
- (instancetype)init NS_UNAVAILABLE;
Expand All @@ -84,16 +146,52 @@ typedef void (^RLMLogFunction)(RLMLogLevel level, NSString *message);
@param level The log level to be set for the logger.
@param logFunction The log function which will be invoked whenever there is a log message.
@note This will set the log level for the log category `RLMLogCategoryRealm`.
*/
- (instancetype)initWithLevel:(RLMLogLevel)level logFunction:(RLMLogFunction)logFunction
__attribute__((deprecated("Use `initWithLogFunction:` instead.")));

/**
Creates a logger with a callback, which will be invoked whenever there is a log message.
@param logFunction The log function which will be invoked whenever there is a log message.
*/
- (instancetype)initWithLevel:(RLMLogLevel)level logFunction:(RLMLogFunction)logFunction;
- (instancetype)initWithLogFunction:(RLMLogCategoryFunction)logFunction;

#pragma mark RLMLogger Default Logger API

/**
The current default logger. When setting a logger as default, this logger will be used whenever information must be logged.
The current default logger. When setting a logger as default, this logger will replace the current default logger and will
be used whenever information must be logged.
*/
@property (class) RLMLogger *defaultLogger NS_SWIFT_NAME(shared);

/**
Log a message to the supplied level.
@param logLevel The log level for the message.
@param category The log category for the message.
@param message The message to log.
*/
- (void)logWithLevel:(RLMLogLevel)logLevel category:(RLMLogCategory)category message:(NSString *)message;

/**
Sets the gobal log level for a given category.
@param level The log level to be set for the logger.
@param category The log function which will be invoked whenever there is a log message.
*/
+ (void)setLevel:(RLMLogLevel)level forCategory:(RLMLogCategory)category NS_REFINED_FOR_SWIFT;

/**
Gets the global log level for the specified category.
@param category The log category which we need the level.
@returns The log level for the specified category
*/
+ (RLMLogLevel)levelForCategory:(RLMLogCategory)category NS_REFINED_FOR_SWIFT;

@end

RLM_HEADER_AUDIT_END(nullability)
Loading

0 comments on commit e3351e3

Please sign in to comment.