diff --git a/README.md b/README.md index ab4907b..b5643d1 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,27 @@ By default notifier connects to a local docker instance (don't forget to specify Notifier accepts usual `DOCKER_HOST` and `DOCKER_CERT_PATH` environment variables to specify remote instance. For http endpoint you need to specify only `--env DOCKER_HOST=tcp://example.com:2375` (make sure to keep such instances behind the firewall). For https, you'll also need to mount a volume with https certificates that contains `ca.pem`, `cert.pem`, and `key.pem`: `--env DOCKER_HOST=tcp://example.com:2376 --env DOCKER_CERT_PATH=/certs --volume $(pwd):/certs` Tutorial on how to generate docker certs can be found [here](https://docs.docker.com/engine/security/https/) +## Container-Specific Notifications + +You can configure different Telegram channels and threads/topics for specific containers using Docker labels: + +```yaml +services: + example: + image: hello-world + labels: + # Monitor control + telegram-notifier.monitor: true + + # Channel override (optional) + telegram-notifier.chat-id: "-100123456789" + + # Thread/Topic override (optional - use only one) + telegram-notifier.topic-id: "12345" + telegram-notifier.thread-id: "12345" +``` + +If these labels are not specified, the container will use the global settings from the notifier's environment variables. ## Credits diff --git a/app.js b/app.js index 5ad56d2..3b9813e 100644 --- a/app.js +++ b/app.js @@ -9,15 +9,36 @@ const docker = new Docker(); const telegram = new TelegramClient(); async function sendEvent(event) { - // console.debug(event); const template = templates[`${event.Type}_${event.Action}`]; if (template) { - const label = event.Actor && event.Actor.Attributes && event.Actor.Attributes['telegram-notifier.monitor']; - const shouldMonitor = label === undefined ? undefined : label.toLowerCase().trim() !== 'false'; + const attributes = event.Actor?.Attributes || {}; + + // Check monitoring status + const monitorLabel = attributes['telegram-notifier.monitor']; + const shouldMonitor = monitorLabel === undefined ? + undefined : + monitorLabel.toLowerCase().trim() !== 'false'; + if (shouldMonitor || !ONLY_WHITELIST && shouldMonitor !== false) { + // Get container-specific channel settings + const overrides = {}; + + // Only add chatId if explicitly set via label + const labelChatId = attributes['telegram-notifier.chat-id']; + if (labelChatId) { + overrides.chatId = labelChatId; + } + + // Only add threadId if explicitly set via label + const labelThreadId = attributes['telegram-notifier.topic-id'] || + attributes['telegram-notifier.thread-id']; + if (labelThreadId) { + overrides.threadId = labelThreadId; + } + const attachment = template(event); console.log(attachment, "\n"); - await telegram.send(attachment) + await telegram.send(attachment, overrides); } } } diff --git a/telegram.js b/telegram.js index f20f0f8..296f123 100644 --- a/telegram.js +++ b/telegram.js @@ -9,31 +9,38 @@ class TelegramClient { null; } - send(message) { + async send(message, overrides = {}) { const options = { parse_mode: 'HTML', disable_web_page_preview: true }; - if (this.threadId) { - options.message_thread_id = parseInt(this.threadId); + const threadId = overrides.threadId || this.threadId; + if (threadId) { + options.message_thread_id = parseInt(threadId); } + const chatId = overrides.chatId || process.env.TELEGRAM_NOTIFIER_CHAT_ID; + return this.telegram.sendMessage( - process.env.TELEGRAM_NOTIFIER_CHAT_ID, + chatId, message, options ); } - sendError(e) { + async sendError(e, overrides = {}) { const options = {}; - if (this.threadId) { - options.message_thread_id = parseInt(this.threadId); + + const threadId = overrides.threadId || this.threadId; + if (threadId) { + options.message_thread_id = parseInt(threadId); } + const chatId = overrides.chatId || process.env.TELEGRAM_NOTIFIER_CHAT_ID; + return this.telegram.sendMessage( - process.env.TELEGRAM_NOTIFIER_CHAT_ID, + chatId, `Error: ${e}`, options );