Skip to content

Commit

Permalink
Redesign the Logger API
Browse files Browse the repository at this point in the history
  • Loading branch information
tgoyne committed Jul 27, 2024
1 parent 0936815 commit 8abdb10
Show file tree
Hide file tree
Showing 9 changed files with 419 additions and 405 deletions.
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
132 changes: 97 additions & 35 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,74 +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.
*/
@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;

/// :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
#pragma mark Deprecated 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.
Gets the logging threshold level used by the logger.
*/
@property (class) RLMLogger *defaultLogger NS_SWIFT_NAME(shared);
@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

0 comments on commit 8abdb10

Please sign in to comment.