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

[RKOTLIN-1038] Implement new log category for RealmLogger #1692

Merged
merged 60 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from 51 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
b7ecb4d
Update to Core 14.0.1
rorbech Feb 28, 2024
5b83ad2
Dump cmake version on GHA build
rorbech Feb 28, 2024
06c75b8
Additional GHA debug info
rorbech Feb 28, 2024
2f02b5b
Update CMAKE on JVM linux docker image
rorbech Feb 28, 2024
8fdd84e
Bump NDK to fix core link issues
rorbech Feb 28, 2024
b8232d3
Bump NDK to fix core link issues
rorbech Feb 28, 2024
f6364d2
Fix expected exception text in query test
rorbech Feb 29, 2024
7f2257c
Clean up debug output
rorbech Feb 29, 2024
d74df61
More clean up
rorbech Feb 29, 2024
7a9933b
Revert NDK to debug arm7v issues
rorbech Mar 4, 2024
2afec66
More debug info
rorbech Mar 4, 2024
85781aa
Included core updates in CHANGELOG
rorbech Mar 6, 2024
0bf3895
Included core updates in CHANGELOG
rorbech Mar 6, 2024
dceaf9d
Cleanup CHANGELOG
rorbech Mar 6, 2024
408fe19
Upgrade to Core 14.2.0
rorbech Mar 15, 2024
5d1e739
Update CHANGELOG.md
rorbech Mar 15, 2024
496cf2c
Add structure for log categories
clementetb Mar 7, 2024
8950932
Add tests
clementetb Mar 7, 2024
f797f60
Add setters/getters
clementetb Mar 13, 2024
ea211de
Pass category in logs callback
clementetb Mar 13, 2024
1b75cd9
Propagate log category in callbacks
clementetb Mar 14, 2024
668a618
Fix compile issues on darwin
clementetb Mar 14, 2024
57682c9
Restore default log level
clementetb Mar 15, 2024
a708d6f
Add documentation
clementetb Mar 15, 2024
7739e2a
Contains support
clementetb Mar 15, 2024
76b51bb
Fix expression did not evaluate to a constant compile error in windows
clementetb Mar 15, 2024
121597e
Clean up
clementetb Mar 15, 2024
63378e9
Read core version from dependencies.yml
rorbech Mar 18, 2024
8910455
Apply suggestions from code review
rorbech Mar 19, 2024
7bbcf89
Updates according to review comments
rorbech Mar 19, 2024
07e223b
Merge branch 'main' into cr/core-upgrade
rorbech Mar 19, 2024
1dfc39b
Bump core
clementetb Mar 21, 2024
93ec563
cleanup
clementetb Mar 21, 2024
bfcc800
Merge branch 'cr/core-upgrade' into ct/loging-categories
clementetb Mar 21, 2024
6a82b18
Merge branch 'main' into ct/loging-categories
clementetb May 2, 2024
c3c5b3b
Merge branch 'main' into ct/loging-categories
clementetb May 2, 2024
c6384fa
Fix changelog merge issue
clementetb May 6, 2024
1cbecdc
defaults
clementetb May 9, 2024
6d3c84d
Update test
clementetb May 9, 2024
e434e90
Add category to log output.
clementetb May 9, 2024
86f48ed
Fix cycle in Logger.log
clementetb May 9, 2024
b935051
Clean up
clementetb May 9, 2024
b31baba
Add test to show SDK logs are not filtered out
clementetb May 9, 2024
9442e73
refactor interface
clementetb May 13, 2024
a6863cd
filter sdk messages
clementetb May 14, 2024
450d6cb
Refactor RealmLogger interface an ContextLogger
clementetb May 14, 2024
8c01bbf
move to internal
clementetb May 14, 2024
510c946
ktlint
clementetb May 14, 2024
6f4d1e3
Clean up
clementetb May 15, 2024
67bd60c
Remove unused imports
clementetb May 15, 2024
f669ee8
Test fixes
clementetb May 15, 2024
8640eb1
Remove leftovers
clementetb May 15, 2024
469e233
Remove redundant code
clementetb May 15, 2024
acf8f57
Remove obsolete code
clementetb May 15, 2024
52c2921
Update test cases
clementetb May 15, 2024
9874107
Use context logger with app services client
clementetb May 15, 2024
b1923ad
Remove obsolete code
clementetb May 16, 2024
2153043
Linting
clementetb May 16, 2024
123d59d
Pr review changes
clementetb May 16, 2024
718d042
Set log level for RealmLogTests
clementetb May 16, 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ This release will bump the Realm file format from version 23 to 24. Opening a fi
### Enhancements
* Support for RealmLists and RealmDictionaries in `RealmAny`. (Issue [#1434](https://github.com/realm/realm-kotlin/issues/1434))
* Optimized `RealmList.indexOf()` and `RealmList.contains()` using Core implementation of operations instead of iterating elements and comparing them in Kotlin. (Issue [#1625](https://github.com/realm/realm-kotlin/pull/1666) [RKOTLIN-995](https://jira.mongodb.org/browse/RKOTLIN-995)).
* Add support for filtering logs by category. (Issue [#1691](https://github.com/realm/realm-kotlin/issues/1691) [JIRA](https://jira.mongodb.org/browse/RKOTLIN-1038))
Copy link
Contributor

Choose a reason for hiding this comment

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

With the new interface this is actually a breaking change, and we should bump the version to 2.0.0-SNAPSHOT.

Copy link
Contributor

Choose a reason for hiding this comment

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

We should also highlight that the LogConfiguration is gone.


### Fixed
* None.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ interface SyncSessionTransferCompletionCallback {

interface LogCallback {
// Passes core log levels as shorts to avoid unnecessary jumping between the SDK and JNI
fun log(logLevel: Short, category: String?, message: String?)
fun log(logLevel: Short, categoryValue: String, message: String?)
rorbech marked this conversation as resolved.
Show resolved Hide resolved
}

interface SyncBeforeClientResetHandler {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,12 @@ expect object RealmInterop {

fun realm_set_log_level(level: CoreLogLevel)

fun realm_set_log_level_category(category: String, level: CoreLogLevel)

fun realm_get_log_level_category(category: String): CoreLogLevel

fun realm_get_category_names(): List<String>

fun realm_app_config_set_metadata_mode(
appConfig: RealmAppConfigurationPointer,
metadataMode: MetadataMode
Expand Down
7 changes: 7 additions & 0 deletions packages/cinterop/src/jvm/jni/java_class_global_def.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class JavaClassGlobalDef {
JavaClassGlobalDef(JNIEnv* env)
: m_java_util_hashmap(env, "java/util/HashMap", false)
, m_java_lang_int(env, "java/lang/Integer", false)
, m_java_lang_string(env, "java/lang/String", false)
, m_kotlin_jvm_functions_function0(env, "kotlin/jvm/functions/Function0", false)
, m_kotlin_jvm_functions_function1(env, "kotlin/jvm/functions/Function1", false)
, m_io_realm_kotlin_internal_interop_sync_network_transport(env, "io/realm/kotlin/internal/interop/sync/NetworkTransport", false)
Expand Down Expand Up @@ -74,6 +75,7 @@ class JavaClassGlobalDef {

jni_util::JavaClass m_java_util_hashmap;
jni_util::JavaClass m_java_lang_int;
jni_util::JavaClass m_java_lang_string;
jni_util::JavaClass m_kotlin_jvm_functions_function0;
jni_util::JavaClass m_kotlin_jvm_functions_function1;
jni_util::JavaClass m_io_realm_kotlin_internal_interop_sync_network_transport;
Expand Down Expand Up @@ -133,6 +135,11 @@ class JavaClassGlobalDef {
return env->NewObject(instance()->m_java_lang_int, init, value);
}

inline static const jni_util::JavaClass& java_lang_string()
{
return instance()->m_java_lang_string;
}

inline static const jni_util::JavaClass& network_transport_class()
{
return instance()->m_io_realm_kotlin_internal_interop_sync_network_transport;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1365,9 +1365,21 @@ actual object RealmInterop {
realmc.realm_set_log_level(level.priority)
}

actual fun realm_set_log_level_category(category: String, level: CoreLogLevel) {
realmc.realm_set_log_level_category(category, level.priority)
}

actual fun realm_get_log_level_category(category: String): CoreLogLevel =
CoreLogLevel.valueFromPriority(realmc.realm_get_log_level_category(category).toShort())

actual fun realm_get_category_names(): List<String> {
val names: Array<String> = realmc.realm_get_log_category_names() as Array<String>
return names.asList()
}

actual fun realm_app_config_set_metadata_mode(
appConfig: RealmAppConfigurationPointer,
metadataMode: MetadataMode
metadataMode: MetadataMode,
) {
realmc.realm_app_config_set_metadata_mode(
appConfig.cptr(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
// TODO https://github.com/realm/realm-kotlin/issues/889
@file:Suppress("TooGenericExceptionThrown", "TooGenericExceptionCaught")
@file:OptIn(ExperimentalForeignApi::class)

package io.realm.kotlin.internal.interop

Expand Down Expand Up @@ -54,6 +55,7 @@ import kotlinx.cinterop.CPointerVar
import kotlinx.cinterop.CPointerVarOf
import kotlinx.cinterop.CValue
import kotlinx.cinterop.CVariable
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.LongVar
import kotlinx.cinterop.MemScope
import kotlinx.cinterop.StableRef
Expand Down Expand Up @@ -2511,7 +2513,7 @@ actual object RealmInterop {
realm_wrapper.realm_set_log_callback(
staticCFunction { userData, category, logLevel, message ->
val userDataLogCallback = safeUserData<LogCallback>(userData)
userDataLogCallback.log(logLevel.toShort(), category?.toKString(), message?.toKString())
userDataLogCallback.log(logLevel.toShort(), category!!.toKString(), message?.toKString())
rorbech marked this conversation as resolved.
Show resolved Hide resolved
},
StableRef.create(callback).asCPointer(),
staticCFunction { userData -> disposeUserData<() -> LogCallback>(userData) }
Expand All @@ -2522,9 +2524,28 @@ actual object RealmInterop {
realm_wrapper.realm_set_log_level(level.priority.toUInt())
}

actual fun realm_set_log_level_category(category: String, level: CoreLogLevel) {
realm_wrapper.realm_set_log_level_category(category, level.priority.toUInt())
}

actual fun realm_get_log_level_category(category: String): CoreLogLevel =
CoreLogLevel.valueFromPriority(realm_wrapper.realm_get_log_level_category(category).toShort())

actual fun realm_get_category_names(): List<String> {
memScoped {
val namesCount = realm_wrapper.realm_get_category_names(0u, null)
val namesBuffer = allocArray<CPointerVar<ByteVar>>(namesCount.toInt())
realm_wrapper.realm_get_category_names(namesCount, namesBuffer)

return List(namesCount.toInt()) {
namesBuffer[it].safeKString()
}
}
}

actual fun realm_app_config_set_metadata_mode(
appConfig: RealmAppConfigurationPointer,
metadataMode: MetadataMode
metadataMode: MetadataMode,
) {
realm_wrapper.realm_app_config_set_metadata_mode(
appConfig.cptr(),
Expand Down
26 changes: 23 additions & 3 deletions packages/jni-swig-stub/src/main/jni/realm_api_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -960,8 +960,8 @@ realm_sync_socket_t* realm_sync_websocket_new(int64_t sync_client_config_ptr, jo
// *** END - WebSocket Client (Platform Networking) *** //

void set_log_callback(jobject log_callback) {
auto jenv = get_env(true);
realm_set_log_callback([](void *userdata, const char* category, realm_log_level_e level, const char *message) {
auto jenv = get_env(false);
realm_set_log_callback([](void *userdata, const char *category, realm_log_level_e level, const char *message) {
auto log_callback = static_cast<jobject>(userdata);
auto jenv = get_env(true);

Expand All @@ -970,7 +970,7 @@ realm_set_log_callback([](void *userdata, const char* category, realm_log_level_
static JavaMethod log_method(jenv,
JavaClassGlobalDef::log_callback(),
"log",
"(SLjava/lang/String;Ljava/lang/String;)V");
"(SLjava/lang/String;Ljava/lang/String;)V");

push_local_frame(jenv, 2);
jenv->CallVoidMethod(log_callback, log_method, java_level, to_jstring(jenv, category), to_jstring(jenv, message));
Expand Down Expand Up @@ -1370,3 +1370,23 @@ realm_class_info_t_cleanup(realm_class_info_t * value) {
delete[] value->primary_key;
delete[] value->name;
}

jobjectArray realm_get_log_category_names() {
JNIEnv* env = get_env(true);

size_t namesCount = realm_get_category_names(0, nullptr);

const char** category_names = new const char*[namesCount];
realm_get_category_names(namesCount, category_names);

auto array = env->NewObjectArray(namesCount, JavaClassGlobalDef::java_lang_string(), nullptr);

for(size_t i = 0; i < namesCount; i++) {
jstring string = env->NewStringUTF(category_names[i]);
env->SetObjectArrayElement(array, i, string);
}

delete[] category_names;

return array;
}
4 changes: 3 additions & 1 deletion packages/jni-swig-stub/src/main/jni/realm_api_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ realm_http_transport_t*
realm_network_transport_new(jobject network_transport);

void
set_log_callback(jobject log_callbac);
set_log_callback(jobject log_callback);

realm_scheduler_t*
realm_create_scheduler(jobject dispatchScheduler);
Expand Down Expand Up @@ -161,4 +161,6 @@ bool realm_sync_websocket_message(int64_t observer_ptr, jbyteArray data, size_t

void realm_sync_websocket_closed(int64_t observer_ptr, bool was_clean, int error_code, const char* reason);

jobjectArray realm_get_log_category_names();

#endif //TEST_REALM_API_HELPERS_H
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@
package io.realm.kotlin.internal.platform

import android.util.Log
import io.realm.kotlin.internal.messageWithCategory
import io.realm.kotlin.log.LogCategory
import io.realm.kotlin.log.LogLevel
import io.realm.kotlin.log.RealmLogger
import java.io.PrintWriter
import java.io.StringWriter
import java.util.Locale
import kotlin.math.min

/**
* Create a logger that outputs to Android LogCat.
Expand All @@ -29,13 +32,22 @@ import java.util.Locale
* for message creation and formatting
*/
internal class LogCatLogger(
override val tag: String = "REALM",
override val level: LogLevel
private val tag: String,
) : RealmLogger {

override fun log(level: LogLevel, throwable: Throwable?, message: String?, vararg args: Any?) {
override fun log(
category: LogCategory,
level: LogLevel,
throwable: Throwable?,
message: String?,
vararg args: Any?,
) {
val priority: Int = level.priority
val logMessage: String = prepareLogMessage(throwable, message, *args)
val logMessage: String = prepareLogMessage(
throwable = throwable,
message = messageWithCategory(category, message),
args = *args
)

// Short circuit if message can fit into a single line in LogCat
if (logMessage.length < MAX_LOG_LENGTH) {
Expand All @@ -50,7 +62,7 @@ internal class LogCatLogger(
var newline = logMessage.indexOf('\n', i)
newline = if (newline != -1) newline else length
do {
val end = Math.min(newline, i + MAX_LOG_LENGTH)
val end = min(newline, i + MAX_LOG_LENGTH)
val part = logMessage.substring(i, end)
printMessage(priority, part)
i = end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import io.realm.kotlin.internal.RealmInitializer
import io.realm.kotlin.internal.RealmInstantImpl
import io.realm.kotlin.internal.interop.SyncConnectionParams
import io.realm.kotlin.internal.util.Exceptions
import io.realm.kotlin.log.LogLevel
import io.realm.kotlin.log.RealmLogger
import io.realm.kotlin.types.RealmInstant
import java.io.FileNotFoundException
Expand Down Expand Up @@ -37,8 +36,8 @@ public actual fun assetFileAsStream(assetFilename: String): InputStream = try {
}

// Returns the default logger for the platform
public actual fun createDefaultSystemLogger(tag: String, logLevel: LogLevel): RealmLogger =
LogCatLogger(tag, logLevel)
public actual fun createDefaultSystemLogger(tag: String): RealmLogger =
LogCatLogger(tag)

public actual fun currentTime(): RealmInstant {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ public interface RealmConfiguration : Configuration {

override fun build(): RealmConfiguration {
verifyConfig()
val realmLogger = ContextLogger("Sdk")
val realmLogger = ContextLogger()

// Sync configs might not set 'name' but local configs always do, therefore it will
// never be null here
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package io.realm.kotlin.internal

import io.realm.kotlin.log.LogCategory
import io.realm.kotlin.log.LogLevel
import io.realm.kotlin.log.RealmLog
import io.realm.kotlin.log.SdkLogCategory

/**
* Internal logger class used to inject context aware information into log message
Expand Down Expand Up @@ -81,10 +83,17 @@ public class ContextLogger(public val context: String? = null) {
}

private inline fun doLog(level: LogLevel, throwable: Throwable?) {
RealmLog.doLog(level, throwable, null)
RealmLog.doLog(LogCategory.Realm.Sdk, level, throwable, null)
}

private inline fun doLog(level: LogLevel, throwable: Throwable?, message: () -> String?, vararg args: Any?) {
RealmLog.doLog(level, throwable, message, *args)
private inline fun doLog(
level: LogLevel,
throwable: Throwable?,
message: () -> String?,
vararg args: Any?,
) {
if (level >= RealmLog.getLevel(SdkLogCategory)) {
RealmLog.doLog(LogCategory.Realm.Sdk, level, throwable, message(), *args)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2024 Realm Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.realm.kotlin.internal

import io.realm.kotlin.internal.interop.CoreLogLevel
import io.realm.kotlin.log.LogCategory
import io.realm.kotlin.log.LogCategoryImpl
import io.realm.kotlin.log.LogLevel

internal fun LogLevel.toCoreLogLevel(): CoreLogLevel {
return when (this) {
LogLevel.ALL -> CoreLogLevel.RLM_LOG_LEVEL_ALL
LogLevel.TRACE -> CoreLogLevel.RLM_LOG_LEVEL_TRACE
LogLevel.DEBUG -> CoreLogLevel.RLM_LOG_LEVEL_DEBUG
LogLevel.INFO -> CoreLogLevel.RLM_LOG_LEVEL_INFO
LogLevel.WARN -> CoreLogLevel.RLM_LOG_LEVEL_WARNING
LogLevel.ERROR -> CoreLogLevel.RLM_LOG_LEVEL_ERROR
LogLevel.WTF -> CoreLogLevel.RLM_LOG_LEVEL_FATAL
LogLevel.NONE -> CoreLogLevel.RLM_LOG_LEVEL_OFF
}
}

internal fun CoreLogLevel.fromCoreLogLevel(): LogLevel {
return when (this) {
CoreLogLevel.RLM_LOG_LEVEL_ALL -> LogLevel.ALL
CoreLogLevel.RLM_LOG_LEVEL_TRACE -> LogLevel.TRACE
CoreLogLevel.RLM_LOG_LEVEL_DEBUG,
CoreLogLevel.RLM_LOG_LEVEL_DETAIL -> LogLevel.DEBUG
CoreLogLevel.RLM_LOG_LEVEL_INFO -> LogLevel.INFO
CoreLogLevel.RLM_LOG_LEVEL_WARNING -> LogLevel.WARN
CoreLogLevel.RLM_LOG_LEVEL_ERROR -> LogLevel.ERROR
CoreLogLevel.RLM_LOG_LEVEL_FATAL -> LogLevel.WTF
CoreLogLevel.RLM_LOG_LEVEL_OFF -> LogLevel.NONE
else -> throw IllegalArgumentException("Invalid core log level: $this")
}
}

internal fun newCategory(
name: String,
parent: LogCategory? = null,
): LogCategory = LogCategoryImpl(name, parent).also { category ->
categoriesByPath["$category"] = category
}

// at package level as a workaround to ensure compatibility with darwin and jvm
internal val categoriesByPath: MutableMap<String, LogCategory> = mutableMapOf()
clementetb marked this conversation as resolved.
Show resolved Hide resolved

internal fun messageWithCategory(
category: LogCategory,
message: String?,
): String? = if (message.isNullOrBlank()) { null } else {
"[${category.name}] $message"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
package io.realm.kotlin.internal.platform

import io.realm.kotlin.internal.interop.SyncConnectionParams
import io.realm.kotlin.log.LogLevel
import io.realm.kotlin.log.RealmLogger
import io.realm.kotlin.types.RealmInstant
import kotlin.jvm.JvmName
Expand Down Expand Up @@ -123,7 +122,7 @@ public expect fun prepareRealmFilePath(directoryPath: String, filename: String):
/**
* Returns the default logger for the platform.
*/
public expect fun createDefaultSystemLogger(tag: String, logLevel: LogLevel = LogLevel.NONE): RealmLogger
public expect fun createDefaultSystemLogger(tag: String): RealmLogger

/**
* Return the current thread id.
Expand Down
Loading
Loading