Extensible Log Management
This document describes how to extend the log management capabilities of thin-edge.io using custom log plugins. By default, thin-edge.io supports retrieving file-based logs. But, it can be extended with plugins to collect logs from other sources like systemd journal, docker containers or any custom log sources.
Overview​
The thin-edge.io agent supports extensible log management through a plugin system:
- The built-in
fileplugin handles traditional file-based logs (the default behavior) - Additional plugins can be installed to support other log sources
- Each plugin can provide multiple log types
- Plugins are discovered and executed automatically by
tedge-agent
How Log Plugins Work​
A log plugin is an executable that implements a simple command-line interface with the following requirements:
- Implement two sub-commands:
list- Returns all log types supported by the plugin (one per line)get <log-type> [--since <timestamp>] [--until <timestamp>]- Retrieves logs for the specified type within the given time range
- Must exit with code 0 for successful
listcommand (used to validate the plugin). - Should output logs to stdout for the
getcommand. - Time filters
--sinceand--untilare passed as seconds since epoch. - Should handle errors gracefully and exit with non-zero codes on failure.
The agent automatically:
- Discovers plugins at startup by running their
listcommand to gather their supported log types. - Publishes the supported log types to the device's
log_uploadcommand metadata topic (e.g:te/device/main///cmd/log_upload) with a plugin suffix in the format<log-type>::<plugin-name>(e.g.,mosquitto::journald) - Routes
log_uploadrequests to thegetcommand of the appropriate plugin based on the type suffix. - The
dateFromanddateToparameters in the command are passed to the plugin as--sinceand--untilarguments. - Further filtering by
searchTextand taillinesare done by the agent itself. - Detects any new plugin installations dynamically.
- Refresh the supported log types by reloading the plugins when any new software is installed or configuration is updated.
Log plugins are installed at /usr/share/tedge/log-plugins, by default.
This plugin root directory can be changed using:
sudo tedge config set log.plugin_paths /usr/local/share/tedge/log-plugins,/usr/share/tedge/log-plugins
Multiple plugin directories can be specified if a layered directory structure is desired,
where plugins from directories earlier in the list gets precedence over the latter ones.
For example, with the above configuration, a file plugin in /usr/local/share/tedge/log-plugins
would override the one with the same name in /usr/share/tedge/log-plugins.
This mechanism can be used to override the factory plugins when needed.
Permissions​
Plugins are executed by the agent with sudo privileges.
The agent automatically creates the following sudoers entry,
giving sudo rights to all plugins installed at /usr/local/lib/tedge/log-plugins:
tedge ALL = (ALL) NOPASSWD:SETENV: /usr/local/lib/tedge/log-plugins/[a-zA-Z0-9]*
If the log.plugin_paths config is updated with additional directories as shown in the previous section,
then sudoers entries must be created for those directories as well.
Additionally, ensure your plugin has appropriate permissions to access the log sources it needs.
Creating a Custom Log Plugin​
Example: docker plugin​
Here's a docker plugin example that can retrieve logs from containers using the docker logs command:
#!/bin/sh
set -eu
help() {
cat <<EOT
docker log plugin to retrieve the logs from containers using the docker cli
$0 <SUBCOMMAND>
SUBCOMMANDS
list
get <type> [--since <timestamp>] [--until <timestamp>]
EOT
}
list_log_types() {
docker ps -a --format "{{.Names}}"
}
get_log_by_type() {
log_type="$1"
shift
# Parse option defaults
since="24h"
until="0s"
while [ $# -gt 0 ]; do
case "$1" in
--since)
since="$2"
shift
;;
--until)
until="$2"
shift
;;
esac
shift
done
# Retrieve logs using docker logs
docker logs "$log_type" \
--since "$since" \
--until "$until"
}
if [ $# -lt 1 ]; then
echo "Missing required subcommand" >&2
help
exit 1
fi
SUBCOMMAND="$1"
shift
case "$SUBCOMMAND" in
list)
list_log_types
;;
get)
get_log_by_type "$@"
;;
*)
echo "Unsupported command" >&2
exit 1
;;
esac
-
The
listcommand of this plugin will output all container names:nginx
mosquitto -
The
getcommand retrieves the logs for the target container using thedocker logscommand.
Installation​
Copy the plugin to the plugins directory and make it executable:
sudo cp /path/to/docker /usr/share/tedge/log-plugins/
sudo chmod +x /usr/share/tedge/log-plugins/docker
Testing the Plugin​
List all log types the plugin supports:
sudo /usr/share/tedge/log-plugins/docker list
Retrieve logs for a specific service:
sudo /usr/share/tedge/log-plugins/docker get ssh
Retrieve logs with time filters (timestamps in seconds since epoch):
sudo /usr/share/tedge/log-plugins/docker get tedge-agent --since 1696250000 --until 1696260000
Dynamic log type discovery​
To ensure that any newly installed services or log sources are immediately available for log collection,
tedge-agent automatically reloads the plugins and refreshes the supported log types on the following events:
- A new log plugin is installed in the plugin directory (
/usr/share/tedge/log-plugins) - The
tedge-log-plugin.tomlfile is updated - A new software is installed with the agent (via the
software_updatecommand) - A new configuration is installed or updated with the agent (via the
config_updatecommand)
If the new software or configuration is installed/updated externally, and not via tedge-agent,
a refresh can be triggered by just touching the plugin configuration file:
touch /etc/tedge/plugins/tedge-log-plugin.toml
Factory Plugins​
- The default
fileplugin is included in thetedgeinstallation package itself on all distributions. - A
journaldplugin that can gather systemd service logs using thejournalctlcommand is also included in thetedgepackages for systemd based distributions like Debian, Ubuntu, RHEL etc.