Skip to content

Add configurable logging system #407

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

Merged
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ libc = "0.2"
uniffi = { version = "0.27.3", features = ["build"], optional = true }
serde = { version = "1.0.210", default-features = false, features = ["std", "derive"] }
serde_json = { version = "1.0.128", default-features = false, features = ["std"] }
log = { version = "0.4.22", default-features = false, features = ["std"]}

vss-client = "0.3"
prost = { version = "0.11.6", default-features = false}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,16 @@
*/
package org.lightningdevkit.ldknode

import kotlin.UInt
import kotlin.test.Test
import kotlin.test.assertEquals
import androidx.test.ext.junit.runners.AndroidJUnit4
import kotlin.io.path.createTempDirectory
import kotlin.test.Test
import org.junit.runner.RunWith
import org.lightningdevkit.ldknode.*;
import android.content.Context.MODE_PRIVATE
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.lightningdevkit.ldknode.*

@RunWith(AndroidJUnit4::class)
class AndroidLibTest {
@Test fun node_start_stop() {
@Test
fun node_start_stop() {
val tmpDir1 = createTempDirectory("ldk_node").toString()
println("Random dir 1: $tmpDir1")
val tmpDir2 = createTempDirectory("ldk_node").toString()
Expand All @@ -28,13 +25,11 @@ class AndroidLibTest {
config1.storageDirPath = tmpDir1
config1.listeningAddresses = listOf(listenAddress1)
config1.network = Network.REGTEST
config1.logLevel = LogLevel.TRACE

val config2 = defaultConfig()
config2.storageDirPath = tmpDir2
config2.listeningAddresses = listOf(listenAddress2)
config2.network = Network.REGTEST
config2.logLevel = LogLevel.TRACE

val builder1 = Builder.fromConfig(config1)
val builder2 = Builder.fromConfig(config2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import java.net.http.HttpRequest
import java.net.http.HttpResponse
import kotlin.io.path.createTempDirectory
import kotlin.test.assertEquals
import kotlin.test.assertTrue

fun runCommandAndWait(vararg cmd: String): String {
println("Running command \"${cmd.joinToString(" ")}\"")
Expand Down Expand Up @@ -92,6 +93,60 @@ fun waitForBlock(esploraEndpoint: String, blockHash: String) {
}
}

class CustomLogWriter(private var currentLogLevel: LogLevel = LogLevel.INFO) :
LogWriter {
enum class LogLevel {
ERROR, WARN, INFO, DEBUG, TRACE, GOSSIP
}

private val logMessages = mutableListOf<String>()

fun setLogLevel(level: LogLevel) {
currentLogLevel = level
}

fun getLogMessages(): List<String> {
return logMessages.toList()
}

override fun log(record: LogRecord) {
val recordLevel =
when (record.level.toString().lowercase()) {
"error" -> LogLevel.ERROR
"warn" -> LogLevel.WARN
"info" -> LogLevel.INFO
"debug" -> LogLevel.DEBUG
"trace" -> LogLevel.TRACE
"gossip" -> LogLevel.GOSSIP
else -> LogLevel.INFO
}

if (isLevelEnabled(recordLevel)) {
val logMessage = formatRecord(record)
logMessages.add(logMessage)
println("$logMessage")
}
}

private fun formatRecord(record: LogRecord): String {
val timestamp =
java.time.LocalDateTime.now()
.format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
return String.format(
"%s %-6s [%s:%s] %s\n",
timestamp,
record.level,
record.modulePath,
record.line,
record.args
)
}

private fun isLevelEnabled(level: LogLevel): Boolean {
return level.ordinal <= currentLogLevel.ordinal
}
}

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class LibraryTest {

Expand All @@ -106,6 +161,9 @@ class LibraryTest {
}

@Test fun fullCycle() {
val logWriter1 = CustomLogWriter(CustomLogWriter.LogLevel.GOSSIP)
val logWriter2 = CustomLogWriter(CustomLogWriter.LogLevel.GOSSIP)

val tmpDir1 = createTempDirectory("ldk_node").toString()
println("Random dir 1: $tmpDir1")
val tmpDir2 = createTempDirectory("ldk_node").toString()
Expand All @@ -118,21 +176,22 @@ class LibraryTest {
config1.storageDirPath = tmpDir1
config1.listeningAddresses = listOf(listenAddress1)
config1.network = Network.REGTEST
config1.logLevel = LogLevel.TRACE

println("Config 1: $config1")

val config2 = defaultConfig()
config2.storageDirPath = tmpDir2
config2.listeningAddresses = listOf(listenAddress2)
config2.network = Network.REGTEST
config2.logLevel = LogLevel.TRACE
println("Config 2: $config2")

val builder1 = Builder.fromConfig(config1)
builder1.setChainSourceEsplora(esploraEndpoint, null)
builder1.setCustomLogger(logWriter1)

val builder2 = Builder.fromConfig(config2)
builder2.setChainSourceEsplora(esploraEndpoint, null)
builder2.setCustomLogger(logWriter2)

val node1 = builder1.build()
val node2 = builder2.build()
Expand Down Expand Up @@ -265,6 +324,9 @@ class LibraryTest {
assert(spendableBalance1AfterClose < 100000u)
assertEquals(102500uL, spendableBalance2AfterClose)

assertTrue(logWriter1.getLogMessages().isNotEmpty())
assertTrue(logWriter2.getLogMessages().isNotEmpty())

node1.stop()
node2.stop()
}
Expand Down
35 changes: 24 additions & 11 deletions bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@ namespace ldk_node {

dictionary Config {
string storage_dir_path;
string? log_file_path;
Network network;
sequence<SocketAddress>? listening_addresses;
NodeAlias? node_alias;
sequence<PublicKey> trusted_peers_0conf;
u64 probing_liquidity_limit_multiplier;
LogLevel log_level;
AnchorChannelsConfig? anchor_channels_config;
SendingParameters? sending_parameters;
};
Expand All @@ -27,6 +25,27 @@ dictionary EsploraSyncConfig {
u64 fee_rate_cache_update_interval_secs;
};

enum LogLevel {
"Gossip",
"Trace",
"Debug",
"Info",
"Warn",
"Error",
};

dictionary LogRecord {
LogLevel level;
string args;
string module_path;
u32 line;
};

[Trait, WithForeign]
interface LogWriter {
void log(LogRecord record);
};

interface Builder {
constructor();
[Name=from_config]
Expand All @@ -41,6 +60,9 @@ interface Builder {
void set_gossip_source_rgs(string rgs_server_url);
void set_liquidity_source_lsps2(SocketAddress address, PublicKey node_id, string? token);
void set_storage_dir_path(string storage_dir_path);
void set_filesystem_logger(string? log_file_path, LogLevel? log_level);
void set_log_facade_logger(LogLevel log_level);
void set_custom_logger(LogWriter log_writer);
void set_network(Network network);
[Throws=BuildError]
void set_listening_addresses(sequence<SocketAddress> listening_addresses);
Expand Down Expand Up @@ -535,15 +557,6 @@ interface MaxDustHTLCExposure {
FeeRateMultiplier ( u64 multiplier );
};

enum LogLevel {
"Gossip",
"Trace",
"Debug",
"Info",
"Warn",
"Error",
};

interface NetworkGraph {
sequence<u64> list_channels();
ChannelInfo? channel(u64 short_channel_id);
Expand Down
Loading
Loading