Send custom message to Telegram bot

363 views
Skip to first unread message

Nacho Álvarez

unread,
Sep 25, 2017, 2:48:26 PM9/25/17
to Riemann Users
Hi, 

I'm trying to send a custom message to a Telegram bot using an event forwarded by Logstash, but I can't be able to do it. 

I know there is any way to send a custom message to an email, using :body and :subject, but I can't find it out with Telegram API, I only get the event description being directly forwarded to Telegram without any possibility to customize it.

I'm new in Clojure, is there any way to do that, as in the red text in the sample?

(def telegram-async
    (batch 10 1
      (async-queue!
        :telegram-async                         ; A name for the forwarder
          {:queue-size     1e4                  ; 10,000 events max
           :core-pool-size 5                    ; Minimum 5 threads
           :max-pools-size 100}                 ; Maximum 100 threads
          (telegram {:token \"275347130:AAEdWBudgeQCV87O0ag9luwwFGcN2Efeqk4\"
                     :chat_id \"261032559\" 
                     :text "This is the sample text alert that I want to send"}))))

Thanks in advance!

Aphyr

unread,
Sep 25, 2017, 3:32:59 PM9/25/17
to rieman...@googlegroups.com
It doesn't look like the telegram adapter has any sort of customization
for the way it formats events, and the way `post` is written makes it
kinda difficult to inject your own function there. I think you'll
probably be looking at patching telegram.clj, or making your own HTTP
call directly, e.g.

(streams
(fn [event]
(client/post ...)))

following the structure of

https://github.com/riemann/riemann/blob/0.2.14/src/riemann/telegram.clj#L38

--Kyle

Nacho Álvarez

unread,
Sep 27, 2017, 10:12:03 AM9/27/17
to Riemann Users
Yep, I thought there was no way to inject any additional param to the telegram adapter. I thought to propose a patch to that adapter, but Clojure it's not in my comfort area, I have a hard lack of experience there.

But I don't thought about to make my own HTTP call, knowing Telegram API it's easy as a pie: just a call to a WS. Thanks for your suggestion, I will try to fight about this lack of experience with Clojure and earn some bits of success. In Python, Java7 or PHP would be easy for me, so, I will be back with feedback about my Clojure adventure.

Thanks again!

Mathieu Corbin

unread,
Sep 27, 2017, 10:38:22 AM9/27/17
to rieman...@googlegroups.com
Hi,

I can help you to patch telegram.clj if you want (but i don't know the telegram API). Could you open an issue describing what do you want in the request body etc... ?

--
You received this message because you are subscribed to the Google Groups "Riemann Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to riemann-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Nacho Álvarez

unread,
Sep 27, 2017, 11:46:07 AM9/27/17
to Riemann Users
Thanks Mathieu, I've tried that. This could be my first Clojure code, so forgive the possible terrible writing. What I want is be able to send a custom message to the chat bot and not the full event description as in the original adapter. I don't know too how compile this in order to change the library jar used by logstash as original Telegram adapter.

I've tried this, how do you see it?

(ns ^{:doc "Send events to Telegram"}
  riemann.telegram
  (:require [clj-http.client :as client]
            [clojure.string :refer [escape join]]))

(def ^:private api-url "https://api.telegram.org/bot%s/%s")

(defn- html-parse-mode []
  "Formats html message."
  (fn [e, my_message_to_bot]
    (str
      "<strong>Host:</strong> " (or (:host e) "-") "\n"
      "<strong>Service:</strong> " (or (:service e) "-") "\n"
      "<strong>State:</strong> " (or (:state e) "-") "\n"
      "<strong>Metric:</strong> " (or (:metric e) "-") "\n"
      ;"<strong>Description:</strong> " (or (:description e) "-")
      "<strong>My message to bot:</strong> " (or (:my_message_to_bot my_message_to_bot) "-")))) ; don't want the full event description, only my custom message

(defn- markdown-parse-mode []
  "Formats markdown message."
  (fn [e, my_message_to_bot]
    (str
      "*Host:* " (or (:host e) "-") "\n"
      "*Service:* " (or (:service e) "-") "\n"
      "*State:* " (or (:state e) "-") "\n"
      "*Metric:* " (or (:metric e) "-") "\n"
      ;"*Description:* " (or (:description e) "-")
      "*My message to bot:* " (or (:my_message_to_bot my_message_to_bot) "-")))) ; don't want the full event description, only my custom message

(defn- format-message [parse-mode event my_message_to_bot] ; add the my_message_to_bot param 
  "Formats a message, accepts a single
  event or a sequence of events."
  (join "\n\n"
        (map
          (if (re-matches #"(?i)html" parse-mode)
            (html-parse-mode)
            (markdown-parse-mode))
            (flatten [event, my_message_to_bot])))) ; not really sure if I can add the my_message_to_bot param here to flatten

(defn- post
  "POST to the Telegram API."
  [token chat_id event parse_mode]
  (client/post (format api-url token "sendMessage")
               {:form-params {:chat_id chat_id
                              :parse_mode (or parse_mode "markdown")
                              :text (format-message parse_mode event)}
                :throw-entire-message? true}))

(defn telegram
  "
  ; defining my custom event string to send to the chat bot
  (def my_event_str (str "You have an event in host " :host " in timestamp: " :timestamp))

  (def telegram-async
    (batch 10 1
      (async-queue!
        :telegram-async                         ; A name for the forwarder
          {:queue-size     1e4                  ; 10,000 events max
           :core-pool-size 5                    ; Minimum 5 threads
           :max-pools-size 100}                 ; Maximum 100 threads
          (telegram {:token \"275347130:AAEdWBudgeQCV87O0ag9luwwFGcN2Efeqk4\"
                     :chat_id \"261032559\" 
                     :my_message_to_bot my_event_str})))) ; add the my_message_to_bot param 
  "
  [opts]
  (fn [event]
    (let [events (if (sequential? event)
                   event
                   [event])]
      (doseq [event events]
        (post (:token opts) (:chat_id opts) event :my_message_to_bot (or (:parse_mode opts) "markdown")))))) ; add the my_message_to_bot param 


To unsubscribe from this group and stop receiving emails from it, send an email to riemann-user...@googlegroups.com.

Mathieu Corbin

unread,
Sep 27, 2017, 5:12:28 PM9/27/17
to rieman...@googlegroups.com
With your code, you will always send the same message (the :my_message_to_bot value) to your bot. You also made a few Clojure mistakes ;)

If i understand correctly, you want to be able to generate your own message.
I think the best think to do is to add an extra option like :message-formatter, which could contains a function to format the event.
I will try to do a PR in the next few days. I will also rewrite some part of telegram.clj, and allow more API options.


To unsubscribe from this group and stop receiving emails from it, send an email to riemann-users+unsubscribe@googlegroups.com.

Nacho Álvarez

unread,
Sep 28, 2017, 2:44:10 AM9/28/17
to Riemann Users
Ooops, it seems it's time to review functional programming concepts and learning a bit of Clojure :S

Yes, you understand correctly, I want to be able to generate my own message, and with this functionality, don't send the raw event description (which may contains sensible and private data) to the Telegram bot. The target will be having an API which allows me to send something like "Ey operator, there is a fall in " :host " now in " :timestamp " please review " :machine_name_no_ip

With the current API, just the event as it happened can be forwarded to the chat bot, and this event may contain IPs and other kind of critical data that I don't want to send outside.

Thanks in advance for your kindly answers!
Reply all
Reply to author
Forward
0 new messages