Alright, so
action policy POLICY_NAME $arg
doesn't pass arguments to the script - had to switch to
action cli command "tclsh flash:/script.tcl $arg"`
which does, HOWEVER...
EEM actions are unable to capture beyond a newline from a variable.
I did find a way out though - trim the newline from $_syslog_msg
(newline is the first char) and assign to a new variable.
Here's the end-to-end solution:
CISCO-1811#sh run | s event
event manager directory user policy "flash:/"
event manager directory user library "flash:/"
event manager directory user repository tftp://1.1.1.3/
event manager applet TRIGGER_ON_SYSLOG
event syslog occurs 1 pattern "%.*"
action 1.0 string trimleft "$_syslog_msg"
action 2.0 cli command "enable"
action 2.1 cli command "tclsh flash:/sendevent.tcl \"$_string_result\""
$_string_result
is an EEM built-in variable that collects the output of string trimleft
From http://www.cisco.com/c/en/us/td/docs/ios-xml/ios/eem/command/eem-cr-book/eem-cr-a2.html:
Use the action string trimleft
command to trim a string from the left end of another string.
This command trims the characters specified by string2
from the left end of string1
. By default, string2
corresponds to white space.
The table below shows the built-in variable in which the result of the action string trimleft
command is stored.
Built-in Variable:
$_string_result
Description:
The result of the action string trimleft
command is stored in this variable.
The above is actually incomplete/misleading/or Cisco has no idea how the language they picked works:
string trimleft
without a second argument trims space, tab, newline, and CR not just white space (See this: http://wiki.tcl.tk/10177).
sendevent.tcl
#...
# my own http_get implementation here
# ...
# My actual event code
set url "http://some.http.destination:8000"
# Event log message is passed in as "$argv 0".
# That's the first item in $argv (which is a list)
set rawmsg [lindex $argv 0]
# Strip quotes from syslog message
set cleanmsg [string map { "\"" "" } $rawmsg]
# Get the time stamp at source
set timestamp [clock format [clock seconds] -format "%Y-%m-%dT%H:%M:%S"]
set json "{
\"RouterTimestamp\": \"$timestamp\",
\"Message\": \"$cleanmsg\"
}\n"
# This makes a POST request. Yes a POST.
# Don't know, ask the TCL developers what's with the name :)
if {[catch {http_get $url -query $json} token]} {
puts "HTTP POST request failed: $token"
} else {
# Everything is fine
puts "POST successful."
}
Result
POST / HTTP/1.1
Accept: */*
Host: some.http.destination
User-Agent: Snobu Speshul TCL HTTP/1.1 Client library // build 21
Connection: close
Content-Length: 151
Content-Type: application/json
{
"RouterTimestamp": "2017-02-02T10:09:49",
"Message": "*Feb 2 10:09:49.307: %CLEAR-5-COUNTERS: Clear counter on all interfaces by console"
}
GitHub repo here (code complete): https://github.com/snobu/cisco-syslog-over-http