aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--elisp/cmk.el212
1 files changed, 123 insertions, 89 deletions
diff --git a/elisp/cmk.el b/elisp/cmk.el
index 7071a38..4ef87e2 100644
--- a/elisp/cmk.el
+++ b/elisp/cmk.el
@@ -18,61 +18,12 @@
;; CMK livestatus
;;
;;; Code:
+(require 'subr-x)
+(require 'cl-lib)
(require 'dash)
-(defun cmk-parse-rows-problems (buffer)
- (with-current-buffer buffer
- (goto-char (point-min))
- (let (data)
- (while (not (eobp))
- (let* ((row
- (split-string (buffer-substring-no-properties (point) (line-end-position)) ";"))
- (state (pcase (string-to-number (car row))
- (0 (propertize "OK" 'face 'font-lock-string-face))
- (1 (propertize "WARN" 'face 'font-lock-warning-face))
- (2 (propertize "CRIT" 'face 'font-lock-keyword-face))
- (3 (propertize "UNKN" 'face 'font-lock-builtin-face))
- (a (number-to-string a))))
- (date (->> (nth 3 row)
- (string-to-number)
- (seconds-to-time)
- (format-time-string "%Y-%m-%d %H:%M")))
- (msg (->> (nth 4 row)
- (replace-regexp-in-string (rx "(" (+ "!") ")") ""))))
- (push (list (count-lines 1 (point))
- (vector state (cadr row)
- (caddr row)
- date msg)) data))
- (forward-line))
- data)))
-
-(defun cmk-oneshot (&optional keep-buffer)
- "One shot socket connection. non-nil KEEP-BUFFER after socket closes."
- (make-network-process
- :name "Checkmk"
- :remote "/tmp/ingridcmk.socket"
- :buffer "CMK"
- :sentinel (lambda (process event)
- (message "Process: %s had the event '%s'" process event)
- (unless keep-buffer
- (kill-buffer (process-buffer process))))))
-
-(let* ((cmks (cmk-oneshot)))
- ;; (process-send-string cmks "GET hosts\nColumns: address name\n\n")
- ;; (process-send-string cmks
- ;; "GET log
- ;; Columns: host_name service_description log_type log_plugin_output log_state log_state_type log_time
- ;; Filter: log_time >= 1657270676
- ;; Filter: class = 1
- ;; Filter: class = 3
- ;; Filter: class = 8
- ;; Or: 3\n\n")
-
- (when (buffer-live-p (get-buffer "CMK Problems")) (kill-buffer "CMK Problems"))
- (with-current-buffer (process-buffer cmks) (erase-buffer))
- (process-send-string cmks "GET services
-Columns: service_state host_name service_description service_last_state_change service_plugin_output
-Filter: service_state = 0
+(defconst cmk-lq-problems-filter
+ "Filter: service_state = 0
Filter: service_has_been_checked = 1
And: 2
Negate:
@@ -89,46 +40,129 @@ Filter: host_state = 2
Filter: host_has_been_checked = 1
And: 2
Negate:\n\n")
- (with-current-buffer (get-buffer-create "CMK Problems")
- (erase-buffer)
- (tabulated-list-mode)
- (setq tabulated-list-format `[("STATE" 5 t)
- ("HOST" 9 t)
- ("Service" 20 t)
- ("Since" 16)
- ("Message" 18 t)
- ])
- (setq tabulated-list-sort-key '("STATE" . nil))
- (accept-process-output cmks 0.1)
- (setq tabulated-list-entries (cmk-parse-rows-problems (process-buffer cmks)))
- (tabulated-list-init-header)
- (tabulated-list-print)
- (display-buffer (current-buffer))))
-(let* ((cmks (cmk-oneshot t)))
- (with-current-buffer (process-buffer cmks) (erase-buffer))
- (process-send-string cmks "GET services
-Columns: service_description host_name service_perf_data
-Filter: service_description ~ CPU utilization
-OutputFormat: csv
-Separators: 10 9 44 124\n\n")
- (accept-process-output cmks 0.1)
- (display-buffer (process-buffer cmks)))
+(defun cmk-state-coloring (state)
+ "Font color for numeric STATE input as string."
+ (cl-check-type state string)
+ (pcase (string-to-number state)
+ (0 (propertize "OK" 'face 'font-lock-string-face))
+ (1 (propertize "WARN" 'face 'font-lock-warning-face))
+ (2 (propertize "CRIT" 'face 'font-lock-keyword-face))
+ (3 (propertize "UNKN" 'face 'font-lock-builtin-face))
+ (_ state)))
+
+(defun cmk-timestamp-to-date (timestamp &optional fmt-str)
+ "TIMESTAMP to human readable date follownig FMT-STR.
+Default is \"%Y-%m-%d %H:%M\"."
+ (thread-last
+ (if (stringp timestamp)
+ (string-to-number timestamp)
+ timestamp)
+ (seconds-to-time)
+ (format-time-string (or fmt-str "%Y-%m-%d %H:%M"))))
+
+(defun cmk-purge-bangs (str)
+ "Remove cmk status output bangs from STR."
+ (replace-regexp-in-string (rx "(" (+ "!") ")") "" str))
-(let* ((now (time-convert nil 'integer))
- (start (- now 7200))
- (cmks (cmk-oneshot t)))
+(defun cmk-oneshot (&optional keep-buffer)
+ "One shot socket connection. non-nil KEEP-BUFFER after socket closes."
+ (make-network-process
+ :name "Checkmk"
+ :remote "/tmp/ingridcmk.socket"
+ :buffer "CMK"
+ :sentinel (lambda (process event)
+ (message "Process: %s had the event '%s'" process (string-trim event))
+ (unless keep-buffer
+ (kill-buffer (process-buffer process))))))
+
+(defun cmk-colums-from-spec (spec)
+ "Extract the column names from SPEC and return a livestatus column command."
+ (concat "Columns: "
+ (mapconcat
+ (lambda (column)
+ (or (plist-get (cdddr column) :column) (car column)))
+ spec
+ " ")))
- (with-current-buffer (process-buffer cmks) (erase-buffer))
- (process-send-string cmks (format "GET services
-Columns: host_name rrddata:1:user:%d:%d:1
-Filter: service_description ~ CPU utilization
-OutputFormat: json\n\n" start now))
- (accept-process-output cmks 0.1)
- (with-current-buffer (process-buffer cmks)
+(defconst cmk-problem-col-spec
+ '(("STATE" 5 t :column "service_state" :parser cmk-state-coloring )
+ ("Host" 9 t :column "host_name")
+ ("Service" 20 t :column "service_description")
+ ("Since" 16 nil :column "service_last_state_change" :parser cmk-timestamp-to-date)
+ ("Check output" 18 t :column "service_plugin_output" :parser cmk-purge-bangs)
+ ))
+
+(defun cmk-parse-rows (buffer column-spec)
+ "Return tabulated entries from BUFFER according to COLUMN-SPEC."
+ (with-current-buffer buffer
(goto-char (point-min))
- (display-buffer (current-buffer))
- (json-parse-buffer)))
+ (cl-loop until (eobp)
+ collect
+ (list (count-lines 1 (point))
+ (cl-map 'vector
+ (lambda (entry spec)
+ (let ((parser (or (plist-get (cdddr spec) :parser) #'identity)))
+ (funcall parser entry)))
+ (split-string (buffer-substring-no-properties (point) (line-end-position)) ";")
+ column-spec))
+ do (forward-line))))
+
+;; (process-send-string cmks "GET hosts\nColumns: address name\n\n")
+;; (process-send-string cmks
+;; "GET log
+;; Columns: host_name service_description log_type log_plugin_output log_state log_state_type log_time
+;; Filter: log_time >= 1657270676
+;; Filter: class = 1
+;; Filter: class = 3
+;; Filter: class = 8
+;; Or: 3\n\n")
+
+(defun cmk-problems ()
+ (interactive)
+ (let ((cmks (cmk-oneshot 'keep))
+ (buffer (get-buffer-create "*CMK Problems*")))
+ (with-current-buffer (process-buffer cmks) (erase-buffer))
+ (process-send-string cmks
+ (concat (string-join `("GET services"
+ ,(cmk-colums-from-spec cmk-problem-col-spec)
+ "Filter: service_description ~ load") "\n")
+ "\n\n"))
+ (with-current-buffer buffer
+ (tabulated-list-mode)
+ (setq tabulated-list-format (vconcat cmk-problem-col-spec))
+ (setq tabulated-list-sort-key '("STATE" . nil))
+ (accept-process-output cmks 0.1)
+ (setq tabulated-list-entries (cmk-parse-rows (process-buffer cmks) cmk-problem-col-spec))
+ (tabulated-list-init-header)
+ (tabulated-list-print)
+ (display-buffer (current-buffer)))))
+
+;;; Get a different csv
+;; (let* ((cmks (cmk-oneshot t)))
+;; (with-current-buffer (process-buffer cmks) (erase-buffer))
+;; (process-send-string cmks "GET services
+;; Columns: service_description host_name service_perf_data
+;; Filter: service_description ~ CPU utilization
+;; OutputFormat: csv
+;; Separators: 10 9 44 124\n\n")
+;; (accept-process-output cmks 0.1)
+;; (display-buffer (process-buffer cmks)))
+
+;;; Get some metric data
+;; (let* ((now (time-convert nil 'integer))
+;; (start (- now 7200))
+;; (cmks (cmk-oneshot t)))
+;; (with-current-buffer (process-buffer cmks) (erase-buffer))
+;; (process-send-string cmks (format "GET services
+;; Columns: host_name rrddata:1:user:%d:%d:1
+;; Filter: service_description ~ CPU utilization
+;; OutputFormat: json\n\n" start now))
+;; (accept-process-output cmks 0.1)
+;; (with-current-buffer (process-buffer cmks)
+;; (goto-char (point-min))
+;; (display-buffer (current-buffer))
+;; (json-parse-buffer)))
(provide 'cmk)