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

RNET-1161: Implement support for using a log level for a specific log category #3634

Merged
merged 44 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
a4bf132
Implement 'LogCategory' classes.
elle-j Jun 26, 2024
0f65081
Update Core wrapper for setting log level.
elle-j Jun 26, 2024
7dfb380
Update 'SharedRealmHandle' for logging and setting log level and cate…
elle-j Jun 26, 2024
b33aba1
Update 'Logger' classes to account for category.
elle-j Jun 26, 2024
a2fbca7
Replace static '_logLevel' member with call into Core.
elle-j Jun 26, 2024
c0d9aa4
Update signature in 'UnityLogger'.
elle-j Jun 26, 2024
596e7f5
Replace use of 'LeafLogCategory' with the base.
elle-j Jun 28, 2024
f4c9574
Remove 'LogCategory' getter.
elle-j Jun 28, 2024
5f8cbf4
Update todo comments.
elle-j Jun 28, 2024
7e909c2
Add first tests.
elle-j Jun 28, 2024
84535af
Log with SDK category if not provided.
elle-j Jun 28, 2024
e728ff2
Pass parent category to create name.
elle-j Jul 1, 2024
dc7af0a
Marshal log category names from Core.
elle-j Jul 1, 2024
dedf349
Test matching Core category names.
elle-j Jul 1, 2024
cc68acb
Add API docs.
elle-j Jul 2, 2024
69bd809
Add more tests.
elle-j Jul 2, 2024
2919b03
Show category hierarchy in API docs.
elle-j Jul 2, 2024
84e8733
Add CHANGELOG entry.
elle-j Jul 2, 2024
5232577
Change arg. order to not break 'LogImpl()' API.
elle-j Jul 2, 2024
d1977ee
Deprecate old APIs.
elle-j Jul 2, 2024
c2dfcfa
Update CHANGELOG.
elle-j Jul 2, 2024
b4dcaad
Point to updated Core.
elle-j Jul 2, 2024
61f05a3
Change marshaled vector from heap-allocated to global.
elle-j Jul 2, 2024
a86513c
Update 'shared_realm_get_log_level'.
elle-j Jul 2, 2024
461e090
Update usage of now-deprecated APIs.
elle-j Jul 2, 2024
b19f081
Update API doc.
elle-j Jul 5, 2024
8fafa12
Use braced initializer when returning marshaled vector.
elle-j Jul 5, 2024
f09ae91
Try to fix Windows marshaling.
elle-j Jul 5, 2024
28455dd
Make marshallable struct unnested.
elle-j Jul 5, 2024
7c91e71
Make marshalable nested.
elle-j Jul 5, 2024
e5a6a8e
Fix Windows marshaling once and for all.
elle-j Jul 5, 2024
40195c3
Fix Windows marshaling twice and for all
nirinchev Jul 10, 2024
4eb128a
Merge branch 'main' into lj/logger
nirinchev Jul 10, 2024
55f074d
Deprecate 'Logger' and use its base class.
elle-j Jul 11, 2024
66cdff5
Check log level for 'Realm.SDK' in 'SyncSocketProvider'.
elle-j Jul 11, 2024
b4efe05
Move marshalling from 'MarshaledVector' onto 'TypeErasedMarshaledVect…
elle-j Jul 11, 2024
c66bdf1
Minor update to API docs.
elle-j Jul 11, 2024
5307414
Update 'cref's to resolve doc links.
elle-j Jul 11, 2024
e7de88a
Add a log API for Core-only messages to avoid checking level.
elle-j Jul 11, 2024
f2a938d
Make arg order in wrapper consistent.
elle-j Jul 11, 2024
a3e3deb
Call non-level-check log impl from 'Log()'.
elle-j Jul 11, 2024
db579ee
Rename 'CoreLog' to 'LogAnyLevel' to suit current call pattern.
elle-j Jul 11, 2024
cf65350
Remove internal 'LogDefault()'.
elle-j Jul 11, 2024
c0b98fb
Update CHANGELOG.
elle-j Jul 11, 2024
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
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
## vNext (TBD)

### Deprecations
* The `Logger` has been deprecated in favor of `RealmLogger`, which `Logger` currently derives from. (PR [#3634](https://github.com/realm/realm-dotnet/pull/3634))
* The `Logger.LogLevel` `set` and `get` accessors have been deprecated. Please use `RealmLogger.SetLogLevel()` and `RealmLogger.GetLogLevel()` (see **Enhancements** below).
* The `Logger.Function(Action<LogLevel, string> logFunction)` have been deprecated. Please use `RealmLogger.Function(Action<LogLevel, LogCategory, string> logFunction)` (see **Enhancements** below).

### Enhancements
* Allow `ShouldCompactOnLaunch` to be set on `SyncConfiguration`, not only `RealmConfiguration`. (Issue [#3617](https://github.com/realm/realm-dotnet/issues/3617))
* Reduce the size of the local transaction log produced by creating objects, improving the performance of insertion-heavy transactions (Core 14.10.0).
* Performance has been improved for range queries on integers and timestamps. Requires that you use the "BETWEEN" operation in `Realm.All<T>().Filter(...)`. (Core 14.10.1)
* Allowed `ShouldCompactOnLaunch` to be set on `SyncConfiguration`, not only `RealmConfiguration`. (Issue [#3617](https://github.com/realm/realm-dotnet/issues/3617))
* Introduced a `LogCategory` and allowed for more control over which category of messages should be logged and at which criticality level. (PR [#3634](https://github.com/realm/realm-dotnet/pull/3634))
* Allowed setting and getting a `LogLevel` for a given `LogCategory`. The hierarchy of categories starts at `LogCategory.Realm`.
```csharp
RealmLogger.SetLogLevel(LogLevel.Warn, LogCategory.Realm.Sync);
RealmLogger.GetLogLevel(LogCategory.Realm.Sync.Client.Session); // LogLevel.Warn
```
* Added a function logger that accepts a callback that will receive the `LogLevel`, `LogCategory`, and the message when invoked.
```csharp
RealmLogger.Default = RealmLogger.Function((level, category, message) => /* custom implementation */);
```
* Added a `RealmLogger.Log()` overload taking a category. If unset, `LogCategory.Realm.SDK` will be used.
```csharp
RealmLogger.Default.Log(LogLevel.Warn, LogCategory.Realm, "A warning message");
```

### Fixed
* A `ForCurrentlyOutstandingWork` progress notifier would not immediately call its callback after registration. Instead you would have to wait for some data to be received to get your first update - if you were already caught up when you registered the notifier you could end up waiting a long time for the server to deliver a download that would call/expire your notifier. (Core 14.8.0)
Expand Down
2 changes: 1 addition & 1 deletion Realm/Realm.UnityUtils/Initializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static void Initialize()
Platform.DeviceInfo = new UnityDeviceInfo();
Platform.BundleId = Application.productName;
InteropConfig.AddPotentialStorageFolder(FileHelper.GetStorageFolder());
Realms.Logging.Logger.Console = new UnityLogger();
Realms.Logging.RealmLogger.Console = new UnityLogger();
Application.quitting += () =>
{
NativeCommon.CleanupNativeResources("Application is exiting");
Expand Down
9 changes: 6 additions & 3 deletions Realm/Realm.UnityUtils/UnityLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@

namespace UnityUtils
{
public class UnityLogger : Logger
/// <summary>
/// A <see cref="RealmLogger"/> that outputs messages via UnityEngine.
/// </summary>
public class UnityLogger : RealmLogger

Check notice

Code scanning / CodeQL

Missing a summary in documentation comment Note

Documentation should have a summary.
{
protected override void LogImpl(LogLevel level, string message)
protected override void LogImpl(LogLevel level, LogCategory category, string message)
{
var toLog = FormatLog(level, message);
var toLog = FormatLog(level, category!, message);
switch (level)
{
case LogLevel.Fatal:
Expand Down
2 changes: 1 addition & 1 deletion Realm/Realm/Handles/RealmHandle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ protected override bool ReleaseHandle()
}
catch(Exception ex)
{
Logger.Default.Log(LogLevel.Error, $"An error occurred while closing native handle. Please file an issue at https://github.com/realm/realm-dotnet/issues. Error: {ex}");
RealmLogger.Default.Log(LogLevel.Error, $"An error occurred while closing native handle. Please file an issue at https://github.com/realm/realm-dotnet/issues. Error: {ex}");
Debug.Fail($"Failed to close native handle: {ex}");

// it would be really bad if we got an exception in here. We must not pass it on, but have to return false
Expand Down
8 changes: 4 additions & 4 deletions Realm/Realm/Handles/SessionHandle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ private static void HandleSessionError(IntPtr sessionHandlePtr, SyncError error,
}
catch (Exception ex)
{
Logger.Default.Log(LogLevel.Warn, $"An error has occurred while handling a session error: {ex}");
RealmLogger.Default.Log(LogLevel.Warn, $"An error has occurred while handling a session error: {ex}");
}
}

Expand Down Expand Up @@ -359,7 +359,7 @@ private static IntPtr NotifyBeforeClientReset(IntPtr beforeFrozen, IntPtr manage
catch (Exception ex)
{
var handlerType = syncConfig is null ? "ClientResetHandler" : syncConfig.ClientResetHandler.GetType().Name;
Logger.Default.Log(LogLevel.Error, $"An error has occurred while executing {handlerType}.OnBeforeReset during a client reset: {ex}");
RealmLogger.Default.Log(LogLevel.Error, $"An error has occurred while executing {handlerType}.OnBeforeReset during a client reset: {ex}");

var exHandle = GCHandle.Alloc(ex);
return GCHandle.ToIntPtr(exHandle);
Expand Down Expand Up @@ -397,7 +397,7 @@ private static IntPtr NotifyAfterClientReset(IntPtr beforeFrozen, IntPtr after,
catch (Exception ex)
{
var handlerType = syncConfig is null ? "ClientResetHandler" : syncConfig.ClientResetHandler.GetType().Name;
Logger.Default.Log(LogLevel.Error, $"An error has occurred while executing {handlerType}.OnAfterReset during a client reset: {ex}");
RealmLogger.Default.Log(LogLevel.Error, $"An error has occurred while executing {handlerType}.OnAfterReset during a client reset: {ex}");

var exHandle = GCHandle.Alloc(ex);
return GCHandle.ToIntPtr(exHandle);
Expand Down Expand Up @@ -460,7 +460,7 @@ private static void HandleSessionPropertyChangedCallback(IntPtr managedSessionHa
}
catch (Exception ex)
{
Logger.Default.Log(LogLevel.Error, $"An error has occurred while raising a property changed event: {ex}");
RealmLogger.Default.Log(LogLevel.Error, $"An error has occurred while raising a property changed event: {ex}");
}
}

Expand Down
36 changes: 31 additions & 5 deletions Realm/Realm/Handles/SharedRealmHandle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
nirinchev marked this conversation as resolved.
Show resolved Hide resolved
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -48,6 +49,17 @@ internal class SharedRealmHandle : StandaloneHandle

private static class NativeMethods
{
// This is a wrapper struct around MarshaledVector since P/Invoke doesn't like it
// when the MarshaledVector is returned as the top-level return value from a native
// function. This only manifests in .NET Framework and is not an issue with Mono/.NET.
// The native return value is MarshaledVector without the wrapper because they are binary
// compatible.
[StructLayout(LayoutKind.Sequential)]
public struct CategoryNamesContainer
{
public MarshaledVector<StringValue> CategoryNames;
}

#pragma warning disable IDE0049 // Use built-in type alias
#pragma warning disable SA1121 // Use built-in type alias

Expand All @@ -64,7 +76,7 @@ private static class NativeMethods
public delegate void DisposeGCHandleCallback(IntPtr handle);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LogMessageCallback(StringValue message, LogLevel level);
public delegate void LogMessageCallback(LogLevel level, StringValue categoryName, StringValue message);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void HandleTaskCompletionCallback(IntPtr tcs_ptr, [MarshalAs(UnmanagedType.U1)] bool invoke_async, NativeException ex);
Expand Down Expand Up @@ -223,8 +235,14 @@ public static extern void rename_property(SharedRealmHandle sharedRealm,
[DllImport(InteropConfig.DLL_NAME, EntryPoint = "shared_realm_refresh_async", CallingConvention = CallingConvention.Cdecl)]
public static extern bool refresh_async(SharedRealmHandle realm, IntPtr tcs_handle, out NativeException ex);

[DllImport(InteropConfig.DLL_NAME, EntryPoint = "shared_realm_get_log_level", CallingConvention = CallingConvention.Cdecl)]
public static extern LogLevel get_log_level([MarshalAs(UnmanagedType.LPWStr)] string category_name, IntPtr category_name_len);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we're trying to go with using Realm.Native.StringValue in wrapper calls when needing to pass strings. Am I correct @nirinchev ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My understanding here was that StringValue is mainly used for the returned strings (Core -> DotNet), whereas the MarshalAs is DotNet -> Core primarily?


[DllImport(InteropConfig.DLL_NAME, EntryPoint = "shared_realm_set_log_level", CallingConvention = CallingConvention.Cdecl)]
public static extern bool set_log_level(LogLevel level);
public static extern void set_log_level(LogLevel level, [MarshalAs(UnmanagedType.LPWStr)] string category_name, IntPtr category_name_len);

[DllImport(InteropConfig.DLL_NAME, EntryPoint = "shared_realm_get_log_category_names", CallingConvention = CallingConvention.Cdecl)]
public static extern CategoryNamesContainer get_log_category_names();

[DllImport(InteropConfig.DLL_NAME, EntryPoint = "shared_realm_get_operating_system", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr get_operating_system(IntPtr buffer, IntPtr buffer_length);
Expand Down Expand Up @@ -271,7 +289,15 @@ public static unsafe void Initialize()
notifyObject, notifyDictionary, onMigration, shouldCompact, handleTaskCompletion, onInitialization);
}

public static void SetLogLevel(LogLevel level) => NativeMethods.set_log_level(level);
public static LogLevel GetLogLevel(LogCategory category) => NativeMethods.get_log_level(category.Name, (IntPtr)category.Name.Length);

public static void SetLogLevel(LogLevel level, LogCategory category) => NativeMethods.set_log_level(level, category.Name, (IntPtr)category.Name.Length);

public static string[] GetLogCategoryNames() => NativeMethods.get_log_category_names()
.CategoryNames
.ToEnumerable()
.Select(name => name.ToDotnetString()!)
.ToArray();

[Preserve]
protected SharedRealmHandle(IntPtr handle) : base(handle)
Expand Down Expand Up @@ -822,9 +848,9 @@ private static void OnDisposeGCHandle(IntPtr handle)
}

[MonoPInvokeCallback(typeof(NativeMethods.LogMessageCallback))]
private static void LogMessage(StringValue message, LogLevel level)
private static void LogMessage(LogLevel level, StringValue categoryName, StringValue message)
{
Logger.LogDefault(level, message!);
RealmLogger.CoreLogDefault(level, LogCategory.FromName(categoryName!), message!);
}

[MonoPInvokeCallback(typeof(NativeMethods.MigrationCallback))]
Expand Down
2 changes: 1 addition & 1 deletion Realm/Realm/Handles/SyncUserHandle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ private static void HandleUserChanged(IntPtr managedUserHandle)
}
catch (Exception ex)
{
Logger.Default.Log(LogLevel.Error, $"An error has occurred while raising User.Changed event: {ex}");
RealmLogger.Default.Log(LogLevel.Error, $"An error has occurred while raising User.Changed event: {ex}");
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion Realm/Realm/Helpers/Argument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public static T ValidateNotNull<T>(T value, string paramName)

public static void AssertDebug(string message)
{
Logger.LogDefault(LogLevel.Error, $"{message} {OpenIssueText}");
RealmLogger.LogDefault(LogLevel.Error, $"{message} {OpenIssueText}");
elle-j marked this conversation as resolved.
Show resolved Hide resolved

#if DEBUG
throw new Exception(message);
Expand Down
Loading
Loading