Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RCOCOA-2273: Add support for Logger categories/ Improve current logger. #8608

Merged
merged 8 commits into from
Jun 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
x.y.z Release notes (yyyy-MM-dd)
=============================================================
### Enhancements
* None.
* 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.

<!-- ### Breaking Changes - ONLY INCLUDE FOR NEW MAJOR version -->
### 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.
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,
Copy link
Member

Choose a reason for hiding this comment

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

[nit] This naming scheme is causing a bit of tautology as we have the RLM prefix and the Realm suffix/infix. One option would be to have

RLMLogCategoryAll,
RLMLogCategorySDK,
...

Essentially dropping the Realm as it's part of every category, thus not bringing any new information. Not a blocker though.

Copy link
Collaborator Author

@dianaafanador3 dianaafanador3 Jun 28, 2024

Choose a reason for hiding this comment

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

Should we change RLMLogCategoryRealm as well?, given that this is the keyword we use for this categories in all SDKs?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I feel a bit ambiguous about it - I'd be fine with either keeping it as RLMLogCategoryRealm or with replacing it with RLMLogCategoryAll. I think in other SDKs we can get away with it because we don't have the RLM prefix (similarly to what we do in Swift). That being said, perhaps we shouldn't overthink it as Obj C users are so few and whether we have Realm in there or not is unlikely to make a huge difference.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In Swift we have Category.realm so to keep uniformity in both APIs, we can keep it like that, and then remove Realm for the rest of the categories

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added changes

/// 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
Loading