diff --git a/library/libsds.h b/library/libsds.h index 886d3cb..3453a9d 100644 --- a/library/libsds.h +++ b/library/libsds.h @@ -55,6 +55,9 @@ int SdsMarkDependenciesMet(void* ctx, int SdsStartPeriodicTasks(void* ctx, SdsCallBack callback, void* userData); +// Configure log file path for nim-sds logging +int SdsSetLogFile(const char* logFilePath); + #ifdef __cplusplus diff --git a/library/libsds.nim b/library/libsds.nim index 53d2a4e..f4e4776 100644 --- a/library/libsds.nim +++ b/library/libsds.nim @@ -5,7 +5,7 @@ when defined(linux): {.passl: "-Wl,-soname,libsds.so".} -import std/[typetraits, tables, atomics], chronos, chronicles +import std/[typetraits, tables, atomics], chronos, chronicles, os, times, strutils import ./sds_thread/sds_thread, ./alloc, @@ -104,13 +104,52 @@ proc libsdsNimMain() {.importc.} # To control when the library has been initialized var initialized: Atomic[bool] -if defined(android): - # Redirect chronicles to Android System logs +proc getLogFilePath(): string = + # Check for environment variable first, fallback to default location + let envPath = getEnv("SDS_LOG_FILE") + if envPath.len > 0: + return envPath + + # Default to a location that status-go can manage + let defaultDir = getEnv("SDS_LOG_DIR", "/tmp") + return joinPath(defaultDir, "nim-sds.log") + +proc writeToLogFile(logLevel: LogLevel, msg: LogOutputStr) {.raises: [].} = + try: + let logFile = getLogFilePath() + let timestamp = now().format("yyyy-MM-dd HH:mm:ss.fff") + let logLine = "[$1] [$2] $3\n".format(timestamp, $logLevel, $msg) + + # Create directory if it doesn't exist + let logDir = parentDir(logFile) + if not dirExists(logDir): + createDir(logDir) + + # Append to log file + let file = open(logFile, fmAppend) + defer: file.close() + file.write(logLine) + except: + # Fallback to console if file writing fails + echo "[nim-sds-fallback] ", logLevel, ": ", msg + +when defined(android): when compiles(defaultChroniclesStream.outputs[0].writer): defaultChroniclesStream.outputs[0].writer = proc( logLevel: LogLevel, msg: LogOutputStr ) {.raises: [].} = echo logLevel, msg +else: + when compiles(defaultChroniclesStream.outputs[0].writer): + defaultChroniclesStream.outputs[0].writer = proc( + logLevel: LogLevel, msg: LogOutputStr + ) {.raises: [].} = + # Critical logs (ERROR, FATAL) are written to console + if logLevel >= LogLevel.ERROR: + echo "[nim-sds] ", logLevel, ": ", msg + else: + # All other logs are written to a file + writeToLogFile(logLevel, msg) proc initializeLibrary() {.exported.} = if not initialized.exchange(true): @@ -322,5 +361,21 @@ proc SdsStartPeriodicTasks( userData, ) +proc SdsSetLogFile( + logFilePath: cstring +): cint {.dynlib, exportc.} = + ## Sets the log file path for nim-sds logging + ## This allows applications to configure where nim-sds logs should be written + initializeLibrary() + + if logFilePath == nil: + return RET_ERR + + try: + putEnv("SDS_LOG_FILE", $logFilePath) + return RET_OK + except: + return RET_ERR + ### End of exported procs ################################################################################ diff --git a/library/sds_thread/inter_thread_communication/requests/sds_message_request.nim b/library/sds_thread/inter_thread_communication/requests/sds_message_request.nim index ea42519..704ce91 100644 --- a/library/sds_thread/inter_thread_communication/requests/sds_message_request.nim +++ b/library/sds_thread/inter_thread_communication/requests/sds_message_request.nim @@ -63,7 +63,7 @@ proc process*( let messageBytes = self.message.toSeq() let (unwrappedMessage, missingDeps, channelId) = unwrapReceivedMessage(rm[], messageBytes).valueOr: - error "UNWRAP_MESSAGE failed", error = error + debug "UNWRAP_MESSAGE failed", error = error return err("error processing UNWRAP_MESSAGE request: " & $error) let res = SdsUnwrapResponse(message: unwrappedMessage, missingDeps: missingDeps, channelId: channelId) diff --git a/src/reliability.nim b/src/reliability.nim index a39fac3..1c25445 100644 --- a/src/reliability.nim +++ b/src/reliability.nim @@ -55,7 +55,7 @@ proc reviewAckStatus(rm: ReliabilityManager, msg: SdsMessage) {.gcsafe.} = ) ) else: - error "Failed to deserialize bloom filter", error = bfResult.error + debug "Failed to deserialize bloom filter", error = bfResult.error rbf = none[RollingBloomFilter]() else: rbf = none[RollingBloomFilter]() @@ -106,7 +106,7 @@ proc wrapOutgoingMessage*( let bfResult = serializeBloomFilter(channel.bloomFilter.filter) if bfResult.isErr: - error "Failed to serialize bloom filter", channelId = channelId + debug "Failed to serialize bloom filter", channelId = channelId return err(ReliabilityError.reSerializationError) let msg = SdsMessage( @@ -230,7 +230,7 @@ proc unwrapReceivedMessage*( return ok((msg.content, missingDeps, channelId)) except Exception: - error "Failed to unwrap message", msg = getCurrentExceptionMsg() + debug "Failed to unwrap message", msg = getCurrentExceptionMsg() return err(ReliabilityError.reDeserializationError) proc markDependenciesMet*( diff --git a/src/rolling_bloom_filter.nim b/src/rolling_bloom_filter.nim index 190ab8a..cc9b98e 100644 --- a/src/rolling_bloom_filter.nim +++ b/src/rolling_bloom_filter.nim @@ -78,7 +78,7 @@ proc clean*(rbf: var RollingBloomFilter) {.gcsafe.} = # Initialize new filter var newFilter = initializeBloomFilter(rbf.maxCapacity, rbf.filter.errorRate).valueOr: - error "Failed to create new bloom filter", error = $error + debug "Failed to create new bloom filter", error = $error return # Keep most recent messages up to minCapacity @@ -93,7 +93,7 @@ proc clean*(rbf: var RollingBloomFilter) {.gcsafe.} = rbf.messages = newMessages rbf.filter = newFilter except Exception: - error "Failed to clean bloom filter", error = getCurrentExceptionMsg() + debug "Failed to clean bloom filter", error = getCurrentExceptionMsg() proc add*(rbf: var RollingBloomFilter, messageId: SdsMessageID) {.gcsafe.} = ## Adds a message ID to the rolling bloom filter.