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

Redesign the Logger API #8645

Closed
wants to merge 4 commits into from
Closed
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
27 changes: 21 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
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.
* Redesign the Logger API to allow dynamically adding and removing log
callbacks and setting separate log levels for different categories.

```swift
Logger.setLogLevel(.info, category: Category.Storage.transactions)
// Unlike setting Logger.shared, this can be done at any time rather than
// having to be done before opening a Realm
Logger.add { level, category, message in
print("Realm Log - \(category.rawValue)-\(level): \(message)")
}
// Set the log level for just sync messages to warn
Logger.set(level: .warn, category: Category.Sync.all)
// Equivalent to old Logger.shared.level = .all
Logger.set(level: .all, category: Category.realm)
```

The old API remains for backwards compatibility but is deprecated. The two
cannot be mixed and setting `Logger.shared` will disable `Logger.add`.
* Code sign our published xcframeworks. By Apple's requirements, we should sign our release
binaries so Xcode can validate it was signed by the same developer on every new version.
binaries so Xcode can validate it was signed by the same developer on every new version.
([Apple](https://developer.apple.com/support/third-party-SDK-requirements/)).
* Report sync warnings from the server such as sync being disabled server-side to the sync error handler.
([#8020](https://github.com/realm/realm-swift/issues/8020)).
Expand All @@ -17,8 +29,11 @@ x.y.z Release notes (yyyy-MM-dd)
* 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.
* `RLMLogger.level`/`Logger.level` has been deprecated in favor of using
`RLMLogger.setLevel:forCategory:`/`Logger.set(level:category:)` and
`RLMLogger.levelForCategory:`/`Logger.level(for:)`.
* Initializing `RLMLogger`/`Logger` instances is deprecated in favor of calling
`+[RLMLogger addLogFunction:]`/`Logger.add()`.

### Compatibility
* Realm Studio: 15.0.0 or later.
Expand Down
1 change: 0 additions & 1 deletion Realm/ObjectServerTests/RLMSyncTestCase.mm
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,6 @@ - (RLMApp *)appWithId:(NSString *)appId {
RLMApp *app = [RLMApp appWithConfiguration:config];
RLMSyncManager *syncManager = app.syncManager;
syncManager.userAgent = self.name;
[RLMLogger setLevel:RLMLogLevelWarn forCategory:RLMLogCategorySync];
return app;
}

Expand Down
139 changes: 96 additions & 43 deletions Realm/RLMLogger.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

#import <Realm/RLMConstants.h>

@class RLMLoggerToken;

RLM_HEADER_AUDIT_BEGIN(nullability)

/// An enum representing different levels of sync-related logging that can be configured.
Expand Down Expand Up @@ -75,7 +77,7 @@ typedef NS_ENUM(NSUInteger, RLMLogCategory) {
RLMLogCategoryRealm,
/// Log category for all sdk related logs.
RLMLogCategorySDK,
/// Log category for all app related logs.
/// Log category for all App related logs.
RLMLogCategoryApp,
/// Log category for all database related logs.
RLMLogCategoryStorage,
Expand Down Expand Up @@ -115,83 +117,134 @@ typedef void (^RLMLogFunction)(RLMLogLevel level, NSString *message);
/// 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;
typedef void (^RLMLogCategoryFunction)(RLMLogLevel level, RLMLogCategory category, NSString *message);

/**
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`.
By default messages are logged to NSLog(), with a log level of
`RLMLogLevelInfo`. You can register an additional callback by calling
`+[RLMLogger addLogFunction:]`:

RLMLogger.defaultLogger = [[RLMLogger alloc] initWithLogFunction:^(RLMLogLevel level, NSString *category, NSString *message) {
[RLMLogger addLogFunction:^(RLMLogLevel level, NSString *category, NSString *message) {
NSLog(@"Realm Log - %lu, %@, %@", (unsigned long)level, category, message);
}];

@note The default log threshold level is `RLMLogLevelInfo` for the log category `RLMLogCategoryRealm`,
and logging strings are output to Apple System Logger.
To remove the default NSLog-logger, call `[RLMLogger removeAll];` first.

To change the log level, call `[RLMLogger setLevel:forCategory:]`. The
`RLMLogCategoryRealm` will update all log categories at once. All log
callbacks share the same log levels and are called for every category.
Comment on lines +133 to +137
Copy link
Contributor

Choose a reason for hiding this comment

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

To remove the default NSLog-logger, call [RLMLogger removeAll]; first.
To change the log level, call [RLMLogger setLevel:forCategory:].
The RLMLogCategoryRealm will update all log categories at once. All log
callbacks share the same log levels and are called for every category.

*/
@interface RLMLogger : NSObject

/// :nodoc:
- (instancetype)init NS_UNAVAILABLE;

#pragma mark Category-based API

/**
Gets the logging threshold level used by the logger.
Registers a new logger callback function.

The logger callback function will be invoked each time a message is logged
with a log level greater than or equal to the current log level set for the
message's category. The log function may be concurrently invoked from multiple
threads.

This function is thread-safe and can be called at any time, including from
within other logger callbacks. It is guaranteed to work even if called
concurrently with logging operations on another thread, but whether or not
those operations are reported to the callback is left unspecified.

This method returns a token which can be used to unregister the callback.
Unlike notification tokens, storing this token is optional. If the token is
destroyed without `invalidate` being called, it will be impossible to
unregister the callback other than with `removeAll` or `resetToDefault`.
*/
@property (nonatomic) RLMLogLevel level
__attribute__((deprecated("Use `setLevel(level:category)` or `setLevel:category` instead.")));
+ (RLMLoggerToken *)addLogFunction:(RLMLogCategoryFunction)function NS_REFINED_FOR_SWIFT;
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like docstrings for the new APIs are missing parameters and returns details


/// :nodoc:
- (instancetype)init NS_UNAVAILABLE;
/**
Removes all registered callbacks.

This function is thread-safe. If called concurrently with logging operations
on other threads, the registered callbacks may be invoked one more time after
this function returns.

This is the only way to remove the default NSLog logging.
*/
+ (void)removeAll;

/**
Creates a logger with the associated log level and the logic function to define your own logging logic.
Resets all of the global logger state to the default.

@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.
This removes all callbacks, adds the default NSLog callback, sets the log
level to Info, and undoes the effects of calling `setDefaultLogger:`.
*/
+ (void)resetToDefault;

@note This will set the log level for the log category `RLMLogCategoryRealm`.
/**
Sets the log level for a given category.

Some categories will also update the log level for child categories. See the
documentation for RLMLogCategory for more details.
*/
- (instancetype)initWithLevel:(RLMLogLevel)level logFunction:(RLMLogFunction)logFunction
__attribute__((deprecated("Use `initWithLogFunction:` instead.")));
+ (void)setLevel:(RLMLogLevel)level forCategory:(RLMLogCategory)category NS_REFINED_FOR_SWIFT;

/**
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.
Gets the log level for the specified category.
*/
- (instancetype)initWithLogFunction:(RLMLogCategoryFunction)logFunction;
+ (RLMLogLevel)levelForCategory:(RLMLogCategory)category NS_REFINED_FOR_SWIFT;

#pragma mark RLMLogger Default Logger API

/**
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);
#pragma mark Deprecated API

/**
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.
Gets the logging threshold level used by the logger.
*/
- (void)logWithLevel:(RLMLogLevel)logLevel category:(RLMLogCategory)category message:(NSString *)message;
@property (nonatomic) RLMLogLevel level
__attribute__((deprecated("Use `setLevel(level:category)` or `setLevel:category` instead.")));

/**
Sets the gobal log level for a given category.
Creates a logger with the associated log level and the logic function to define your own logging logic.

@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.
@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`.
*/
+ (void)setLevel:(RLMLogLevel)level forCategory:(RLMLogCategory)category NS_REFINED_FOR_SWIFT;
- (instancetype)initWithLevel:(RLMLogLevel)level logFunction:(RLMLogFunction)logFunction
__attribute__((deprecated("Use `+[Logger addLogFunction:]` instead.")));

/**
Gets the global log level for the specified category.
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.

@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;
Overriding the default logger will result in callbacks registered with
`addLogFunction:` never being invoked.
*/
@property (class) RLMLogger *defaultLogger NS_SWIFT_NAME(shared)
__attribute__((deprecated("Use `+[Logger addLogFunction:]` instead.")));
@end

/**
A token which can be used to remove logger callbacks.

This token only needs to be stored if you wish to be able to remove individual
callbacks. If the token is destroyed without `invalidate` being called the
callback will not be removed.
*/
RLM_SWIFT_SENDABLE RLM_FINAL
@interface RLMLoggerToken : NSObject
/**
Removes the associated logger callback.

This function is thread-safe and idempotent. Calling it multiple times or from
multiple threads at once is not an error. If called concurrently with logging
operations on another thread, the associated callback may be called one more
time per thread after this function returns.
*/
- (void)invalidate;
@end

RLM_HEADER_AUDIT_END(nullability)
Loading
Loading