⭐ Star us on GitHub — it motivates us a lot!
A JS logger made for easy logging from browsers to a server endpoint
Churchill consists of two main components:
- @churchill/client - Browser-side logging library (distributed via CDN)
- @churchill/server - Node.js server component (distributed via NPM)
npm i churchill-loggerSimply add this tag to
<script src="https://unpkg.com/churchill-client@latest/dist/churchill.min.js"></script>If you just want to start sending logs from the browser to a server it can be done as such
<script src="https://unpkg.com/churchill-client@latest/dist/churchill.min.js"></script>
<script>
const logger = Churchill.create();
logger.config({
serverUrl: "<URL>", // The log endpoint of the server
console: true, // Toggles logging to the browser console
level: 'debug', // The log-level which determines what types of logs that will be logged
useragent: false // Toggles of adding the user agent to the log object
})
logger.info("Hello World!")
</script>Then you create an endpoint with your favorite web application framework and within you put this
const churchill = require('churchill-logger/dist');
const logger = churchill.create();
// Create log endpoint, and pass log objects to Churchill
app.post('/logs', (req, res) => {
const success = logger.processLog(req.body)
res.status(success ? 200 : 400).json({
status: success ? 'ok' : 'error'
})
})Note
Check our examples folder for other framework examples
This will then start logging messages from the browser into the servers terminal
The loglevels are lables that define the importance of log messages The levels can be assigned both to messages but alos the loggers themselves
Loglevels for messages are assigned using the built in level functions for the loggers.
logger.trace("Hello")
logger.debug("Hello")
logger.info("Hello")
logger.warn("Hello")
logger.error("Hello")Using these levels the logger can differentiate between the importance of the loggers, and by assigning a level to the logger itself
logger.config({
level: "info"
})you can sort out logs with lower importance than the logger itself.
Other than this the level functions have the same functionality as any other log function except the trace level that also gives the stacktrace
// Configure server-side logger with transports
const logger = churchill.create({
level: 'debug',
transports: [
new churchill.transports.Console(),
new churchill.transports.File({ filename: 'logs/app.log' })
]
});Churchill uses transports to determine where logs are sent. The library comes with built-in transports:
Logs to the terminal/console with formatted output (default).
const logger = churchill.create({
level: 'debug',
transports: [
new churchill.transports.Console()
]
});Logs to a file in JSON format.
const logger = churchill.create({
level: 'info',
transports: [
new churchill.transports.File({ filename: 'logs/app.log' })
]
});The file transport can also be used with logrotation and compression it can be enabled as such
const logger = churchill.create({
level: 'info',
transports: [
new churchill.transports.File({
filename: 'logs/app.log',
logRotation: true, //Enables log rotation
compress: true, //Enables compression of the old file when you rotate to a new one
maxsize: 10 * 1024 * 1024,//Max logsize before rotation, 10MB by default
rotateDaily: true, //Enables daily log rotations
})
]
});Logs to a DuckDB database for structured storage and querying.
Note
The DuckDB transport is only available if you have installed the duckdb package. If not installed, Churchill will work normally but the DuckDB transport won't be available.
Installation for DuckDB:
npm install duckdbUsage:
const logger = churchill.create({
level: 'info',
transports: [
new churchill.transports.DuckDB({
database: 'logs/logs.duckdb',
tableName: 'churchill_logs'
})
]
});The DuckDB transport creates a table with the following schema:
id- Auto-incrementing primary keytimestamp- Log timestamp with timezonelevel- Log level (error, warn, info, etc.)message- Extracted log messagedata- JSON data payloadmetadata- JSON metadatacreated_at- Unix timestamp
const logger = churchill.create({
level: 'debug',
transports: [
new churchill.transports.Console({ level: 'error' }), // Only errors to console
new churchill.transports.File({ filename: 'logs/app.log' }), // All logs to file
new churchill.transports.DuckDB({ database: 'logs/analytics.duckdb' }) // All logs to database
]
});You can create your own transports, by extending from the Churchill.Transport class.
You need to overwrite the Log() function.
class CustomTransport extends churchill.Transport {
constructor(options) {
super(options);
// # Initialize your logger here #
}
log(level, data, metadata) {
// # Implement logging logic here #
}
}You can then use it like the other transports, by adding it to the transport array argument.
const logger = churchill.create({
transports: [new CustomTransport()]
});This project is licensed under a modified MIT License - check LICENSE for details.
