| .. | ||
| api | ||
| impl-composite | ||
| impl-console | ||
| impl-file | ||
| impl-legacy | ||
| testing | ||
| README.md | ||
Thunderbird Core Logging Module
This module provides a flexible and extensible logging system for Thunderbird for Android.
Architecture
The logging system is organized into several modules:
- api: Core interfaces and classes
- impl-console: Console logging implementation
- impl-composite: Composite logging (multiple sinks)
- impl-legacy: Legacy logging system compatibility
- testing: Testing utilities
Core Components
classDiagram
class Logger {
+verbose(tag, throwable, message: () -> LogMessage)
+debug(tag, throwable, message: () -> LogMessage)
+info(tag, throwable, message: () -> LogMessage)
+warn(tag, throwable, message: () -> LogMessage)
+error(tag, throwable, message: () -> LogMessage)
}
class DefaultLogger {
-sink: LogSink
-clock: Clock
}
class LogSink {
+level: LogLevel
+canLog(level): boolean
+log(event: LogEvent)
}
class LogEvent {
+level: LogLevel
+tag: LogTag?
+message: LogMessage
+throwable: Throwable?
+timestamp: Long
}
class LogLevel {
VERBOSE
DEBUG
INFO
WARN
ERROR
}
Logger <|-- DefaultLogger
DefaultLogger --> LogSink
LogSink --> LogEvent
LogSink --> LogLevel
LogEvent --> LogLevel
Implementation Modules
classDiagram
class LogSink {
+level: LogLevel
+canLog(level): boolean
+log(event: LogEvent)
}
class ConsoleLogSink {
+level: LogLevel
}
class CompositeLogSink {
+level: LogLevel
-manager: LogSinkManager
}
LogSink <|-- ConsoleLogSink
LogSink <|-- CompositeLogSink
CompositeLogSink --> LogSinkManager
class LogSinkManager {
+getAll(): List<LogSink>
+add(sink: LogSink)
+addAll(sinks: List<LogSink>)
+remove(sink: LogSink)
+removeAll()
}
class DefaultLogSinkManager {
-sinks: MutableList<LogSink>
}
LogSinkManager <|-- DefaultLogSinkManager
Getting Started
Basic Setup
To start using the logging system, you need to:
- Add the necessary dependencies to your module's build.gradle.kts file
- Create a LogSink
- Create a Logger
- Start logging!
Basic Logging
// Create a log sink
val sink = ConsoleLogSink(LogLevel.DEBUG)
// Create a logger
val logger = DefaultLogger(sink)
// Log messages
logger.debug(tag = "MyTag") { "Debug message" }
logger.info { "Info message" }
logger.warn { "Warning message" }
logger.error(throwable = exception) { "Error message with exception" }
Note that the message parameter is a lambda that returns a String. This allows for lazy evaluation of the message, which can improve performance when the log level is set to filter out certain messages.
Composite Logging (Multiple Sinks)
If you want to send logs to multiple destinations, use the CompositeLogSink:
// Create log sinks
val consoleSink = ConsoleLogSink(LogLevel.INFO)
val otherSink = YourCustomLogSink(LogLevel.DEBUG)
// Create a composite sink
val compositeSink = CompositeLogSink(
level = LogLevel.DEBUG,
sinks = listOf(
consoleSink,
otherSink
)
)
// Create a logger
val logger = DefaultLogger(compositeSink)
// Log messages (will go to both sinks if level is appropriate)
logger.debug { "This goes only to otherSink if its level is DEBUG or lower" }
logger.info { "This goes to both sinks if their levels are INFO or lower" }
Creating Custom Log Sinks
You can create your own log sink by implementing the LogSink interface:
class MyCustomLogSink(
override val level: LogLevel,
// Add any other parameters you need
) : LogSink {
override fun log(event: LogEvent) {
// Implement your custom logging logic here
// For example, send logs to a remote server, write to a database, etc.
val formattedMessage = "${event.timestamp} [${event.level}] ${event.tag ?: ""}: ${event.message}"
// Handle the throwable if present
event.throwable?.let {
// Process the throwable
}
// Send or store the log message
}
}
Best Practices
Log Levels
Use appropriate log levels for different types of messages:
- VERBOSE: Detailed information, typically useful only for debugging
- DEBUG: Debugging information, useful during development
- INFO: General information about application operation
- WARN: Potential issues that aren't errors but might need attention
- ERROR: Errors and exceptions that should be investigated
Troubleshooting
Common Issues
- No logs appearing:
- Check that the log level of your sink is appropriate for the messages you're logging
- Verify that your logger is properly initialized
Debugging the Logging System
To debug issues with the logging system itself:
- Create a simple ConsoleLogSink with VERBOSE level
- Log test messages at different levels
- Check if messages appear as expected