branch: elpa/logview
commit 5d782715e017949a0d9c6146796299f366ac0d1b
Merge: 794a3fff29 01aa1ad1a6
Author: Paul Pogonyshev <pogonys...@gmail.com>
Commit: GitHub <nore...@github.com>

    Merge pull request #32 from xmacex/add-5424-levels
    
    Add RFC 5424 levels
---
 README.md                       |   4 +-
 logview.el                      |  57 ++++++++++----
 test/apache/error.log           |  12 +++
 test/levels/rfc-5424-levels.log |  10 +++
 test/logview.el                 | 169 ++++++++++++++++++++++++++++++++++++++++
 test/monolog/1.log              |  10 +++
 6 files changed, 244 insertions(+), 18 deletions(-)

diff --git a/README.md b/README.md
index 43698a7afd..a38276cd8e 100644
--- a/README.md
+++ b/README.md
@@ -18,8 +18,8 @@ The mode is meant to be operated in read-only buffer, so all 
the
 command bindings lack modifiers.
 
 Out-of-the-box the mode should be able to parse standard SLF4J (Log4j,
-Logback) files as long as they use ISO 8601 timestamps and certain
-UNIX files in `/var/log`.
+Logback) files as long as they use ISO 8601 timestamps, Apache error
+logs, PHP Monolog logs, and certain UNIX files in `/var/log`.
 
 
 ### Installation
diff --git a/logview.el b/logview.el
index 8713e07fad..c53e47bc92 100644
--- a/logview.el
+++ b/logview.el
@@ -72,23 +72,40 @@
                 (levels  . "SLF4J")
                 (aliases . ("Log4j" "Log4j2" "Logback"))))
     ;; We misuse thread as a field for hostname.
-    ("UNIX"  . ((format  . "TIMESTAMP THREAD NAME:"))))
+    ("UNIX"  . ((format  . "TIMESTAMP THREAD NAME:")))
+    ("Apache Error Log"  . ((format . "[TIMESTAMP] [NAME:LEVEL] [THREAD] 
MESSAGE")
+                           (levels . "RFC 5424 lowercase")))
+    ("Monolog" . ((format  . "[TIMESTAMP] NAME[THREAD].LEVEL: MESSAGE")
+                  (levels  . "RFC 5424")
+                  (aliases . ("PHP" "PSR-3")))))
   "Alist of standard submodes.
 This value is used as the fallback for customizable
 `logview-additional-submodes'.")
 
 (defvar logview-std-level-mappings
-  '(("SLF4J" . ((error       "ERROR")
-                (warning     "WARN")
-                (information "INFO")
-                (debug       "DEBUG")
-                (trace       "TRACE")
-                (aliases     "Log4j" "Log4j2" "Logback")))
-    ("JUL"   . ((error       "SEVERE")
-                (warning     "WARNING")
-                (information "INFO")
-                (debug       "CONFIG" "FINE")
-                (trace       "FINER" "FINEST"))))
+  '(("SLF4J"    . ((error       "ERROR")
+                   (warning     "WARN")
+                   (information "INFO")
+                   (debug       "DEBUG")
+                   (trace       "TRACE")
+                   (aliases     "Log4j" "Log4j2" "Logback")))
+    ("JUL"      . ((error       "SEVERE")
+                   (warning     "WARNING")
+                   (information "INFO")
+                   (debug       "CONFIG" "FINE")
+                   (trace       "FINER" "FINEST")))
+    ("RFC 5424" . ((error       "EMERGENCY" "ALERT" "CRITICAL" "ERROR")
+                   (warning     "WARNING")
+                   (information "NOTICE" "INFO")
+                   (debug       "DEBUG")
+                   (trace)
+                   (aliases     "syslog")))
+    ("RFC 5424 lowercase" . ((error "emergency" "alert" "critical" "error")
+                   (warning     "warning")
+                   (information "notice" "info")
+                   (debug       "debug")
+                   (trace)
+                   (aliases     "Apache error log"))))
   "Standard mappings of actual log levels to mode's final levels.
 This alist value is used as the fallback for customizable
 `logview-additional-level-mappings'.")
@@ -104,6 +121,7 @@ This alist value is used as the fallback for customizable
                     ("ISO 8601 time only + millis"            "HH:mm:ss.SSS")
                     ("ISO 8601 time only + micros"            
"HH:mm:ss.SSSSSS")
                     ("ISO 8601 time only"                     "HH:mm:ss")
+                    (nil                                      "EEE MMM dd 
HH:mm:ss.SSSSSS yyyy")
                     (nil                                      "MMM d HH:mm:ss")
                     (nil                                      "MMM d h:mm:ss 
a")
                     (nil                                      "h:mm:ss a")))
@@ -203,9 +221,9 @@ levels  [may be optional]
     lacks levels altogether.
 
     There are some predefined values valid for this field:
-    \"SLF4J\" (and its alises \"Log4j\", \"Log4j2\", \"Logback\"
-    and \"JUL\".  See variable `logview-std-level-mappings' for
-    details.
+    \"SLF4J\" (and its aliases \"Log4j\", \"Log4j2\",
+    \"Logback\", \"JUL\" and the syslog standard \"RFC 5424\".
+    See variable `logview-std-level-mappings' for details.
 
 timestamp  [optional]
 
@@ -260,7 +278,14 @@ complicated:
 JUL has seven severity levels and we need to map them to five the
 mode supports.  So the last two lists contain two levels each.
 It is also legal to have empty lists, usually if there are less
-than five levels.
+than five levels, or if some of the levels do not conceptually
+map to the levels of the mode.  This is the case with RFC 5424:
+
+        Error levels:        EMERGENCY, ALERT, CRITICAL, ERROR
+        Warning levels:      WARNING
+        Information levels:  NOTICE, INFO
+        Debug levels:        DEBUG
+        Trace levels:
 
 Mapping can have any number of optional aliases, which work just
 as the name."
diff --git a/test/apache/error.log b/test/apache/error.log
new file mode 100644
index 0000000000..f537bef9ec
--- /dev/null
+++ b/test/apache/error.log
@@ -0,0 +1,12 @@
+[Wed Oct 30 11:25:15.446929 2019] [core:emergency] [pid 183] Emergency message.
+[Wed Oct 30 11:25:15.446929 2019] [core:alert] [pid 183] Alert message.
+[Wed Oct 30 11:25:15.446929 2019] [core:critical] [pid 183] Critical message.
+[Wed Oct 30 11:25:15.446929 2019] [core:error] [pid 183] Error message.
+[Wed Oct 30 11:25:15.446929 2019] [core:warning] [pid 183] Warning message.
+[Wed Oct 30 11:25:15.446929 2019] [core:notice] [pid 183] Notice message.
+[Wed Oct 30 11:25:15.446929 2019] [core:info] [pid 183] Info message.
+[Wed Oct 30 11:25:15.446929 2019] [core:debug] [pid 183] Debug message.
+kittens unicorns and who knows what.
+
+What even are these line? A weird log format maybe, or details of the one 
above?
+[Wed Oct 30 11:25:15.446929 2019] [core:info] [pid 183] Info message after 
some undefined lines.
diff --git a/test/levels/rfc-5424-levels.log b/test/levels/rfc-5424-levels.log
new file mode 100644
index 0000000000..10a7ae2e29
--- /dev/null
+++ b/test/levels/rfc-5424-levels.log
@@ -0,0 +1,10 @@
+[2019-12-23 10:51:54] name[thread].EMERGENCY: Emergency message.
+[2019-12-23 10:51:55] name[thread].ALERT: Alert message.
+[2019-12-23 10:51:55] name[thread].CRITICAL: Critical message.
+[2019-12-23 10:51:56] name[thread].ERROR: Error message.
+[2019-12-23 10:51:56] name[thread].WARNING: Warning message.
+[2019-12-23 10:51:56] name[thread].NOTICE: Notice message.
+[2019-12-23 10:51:56] name[thread].INFO: Info message.
+[2019-12-23 10:51:56] name[thread].DEBUG: Debug message.
+[2019-12-23 10:51:56] name[thread].KITTENS: No such level defined by RFC 5424.
+[2019-12-23 10:51:56] name[thread].INFO: Info message after an invalid level.
diff --git a/test/logview.el b/test/logview.el
index a0e6b505fd..7889389fca 100644
--- a/test/logview.el
+++ b/test/logview.el
@@ -103,3 +103,172 @@
     (should (equal logview--submode-name "custom"))
     (logview--locate-current-entry entry start
       (should (and entry (equal start 1))))))
+
+;; RFC 5424 levels.
+;;
+;; The mock log file should have a list of log messages in the default
+;; Monolog format, in decreasing order of importance, from EMERGENCY
+;; to DEBUG. The second last entry should be an entry with a level
+;; which isn't defined in RFC 5424.
+;;
+;; TODO:  An epic case of DRY in these tests, maybe a function would be a good 
idea?
+(ert-deftest logview-test-rfc5424-level-0-emergency ()
+  (logview--test-with-file "levels/rfc-5424-levels.log" ()
+    (should (equal logview--submode-name "Monolog"))
+    (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 0))
+    (logview-go-to-message-beginning)
+    (should (looking-at "Emergency message.$"))))
+
+(ert-deftest logview-test-rfc5424-level-1-alert ()
+  (logview--test-with-file "levels/rfc-5424-levels.log" ()
+    (should (equal logview--submode-name "Monolog"))
+    (logview-next-entry 1)
+    (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 1))
+    (logview-go-to-message-beginning)
+    (should (looking-at "Alert message.$"))))
+
+(ert-deftest logview-test-rfc5424-level-2-critical ()
+  (logview--test-with-file "levels/rfc-5424-levels.log" ()
+    (should (equal logview--submode-name "Monolog"))
+    (logview-next-entry 2)
+    (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 2))
+    (logview-go-to-message-beginning)
+    (should (looking-at "Critical message.$"))))
+
+(ert-deftest logview-test-rfc5424-level-3-error ()
+  (logview--test-with-file "levels/rfc-5424-levels.log" ()
+    (should (equal logview--submode-name "Monolog"))
+    (logview-next-entry 3)
+    (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 3))
+    (logview-go-to-message-beginning)
+    (should (looking-at "Error message.$"))))
+
+(ert-deftest logview-test-rfc5424-level-4-warning ()
+  (logview--test-with-file "levels/rfc-5424-levels.log" ()
+    (should (equal logview--submode-name "Monolog"))
+    (logview-next-entry 4)
+    (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 4))
+    (logview-go-to-message-beginning)
+    (should (looking-at "Warning message.$"))))
+
+(ert-deftest logview-test-rfc5424-level-5-notice ()
+  (logview--test-with-file "levels/rfc-5424-levels.log" ()
+    (should (equal logview--submode-name "Monolog"))
+    (logview-next-entry 5)
+    (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 5))
+    (logview-go-to-message-beginning)
+    (should (looking-at "Notice message.$"))))
+
+(ert-deftest logview-test-rfc5424-level-6-info ()
+  (logview--test-with-file "levels/rfc-5424-levels.log" ()
+    (should (equal logview--submode-name "Monolog"))
+    (logview-next-entry 6)
+    (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 6))
+    (logview-go-to-message-beginning)
+    (should (looking-at "Info message.$"))))
+
+(ert-deftest logview-test-rfc5424-level-7-debug ()
+  (logview--test-with-file "levels/rfc-5424-levels.log" ()
+    (should (equal logview--submode-name "Monolog"))
+    (logview-next-entry 7)
+    (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 7))
+    (logview-go-to-message-beginning)
+    (should (looking-at "Debug message.$"))))
+
+(ert-deftest logview-test-rfc5424-level-undefined ()
+  (logview--test-with-file "levels/rfc-5424-levels.log" ()
+    (should (equal logview--submode-name "Monolog"))
+    ;; (logview-next-entry 8)
+    (forward-line 8)
+    (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 7))
+    (logview-go-to-message-beginning)
+    ;; (should (looking-at "No such level defined by RFC 5424.$"))))
+    (should (looking-at ""))))
+
+(ert-deftest logview-test-rfc5424-level-defined-level-after-an-undefined-one ()
+  (logview--test-with-file "levels/rfc-5424-levels.log" ()
+    (should (equal logview--submode-name "Monolog"))
+    (logview-next-entry 8)
+    (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 6))
+    (logview-go-to-message-beginning)
+    (should (looking-at "Info message after an invalid level.$"))))
+
+;; Apache error log submode
+(ert-deftest logview-test-apache-submode-recognition ()
+  (logview--test-with-file "apache/error.log" ()
+    (should (equal logview--submode-name "Apache Error Log"))))
+
+(ert-deftest logview-test-apache-submode-find-entries ()
+  (logview--test-with-file "apache/error.log" ()
+    (logview--locate-current-entry entry start
+      (should (and entry (equal start 1))))))
+
+(ert-deftest logview-test-apache-submode-match-a-message ()
+  (logview--test-with-file "apache/error.log" ()
+    (logview--locate-current-entry entry start
+      (logview-go-to-message-beginning)
+      (should (looking-at "Emergency message.$")))))
+
+(ert-deftest logview-test-apache-submode-match-a-message-after-undefined-lines 
()
+  (logview--test-with-file "apache/error.log" ()
+    (logview--locate-current-entry entry start
+      (logview-next-entry 8)
+      (logview-go-to-message-beginning)
+      (should (looking-at "Info message after some undefined lines.")))))
+
+;; TODO: This, or something should test the eventual final levels
+;; LogView Mode works with. With that transition, maybe the RFC 5424
+;; and RFC 5424 lowercase level definitions could be merged.
+(ert-deftest logview-test-apache-submode-match-all-levels ()
+  (logview--test-with-file "apache/error.log" ()
+    (logview--locate-current-entry entry start
+      (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 0))
+      (logview-next-entry)
+      (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 1))
+      (logview-next-entry)
+      (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 2))
+      (logview-next-entry)
+      (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 3))
+      (logview-next-entry)
+      (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 4))
+      (logview-next-entry)
+      (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 5))
+      (logview-next-entry)
+      (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 6))
+      (logview-next-entry)
+      (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 7)))))
+
+;; Monolog submode
+(ert-deftest logview-test-monolog-submode-recognition ()
+  (logview--test-with-file "monolog/1.log" ()
+    (should (equal logview--submode-name "Monolog"))))
+
+(ert-deftest logview-test-monolog-submode-find-entries ()
+  (logview--test-with-file "monolog/1.log" ()
+    (logview--locate-current-entry entry start
+      (should (and entry (equal start 1))))))
+
+(ert-deftest logview-test-monolog-submode-match-a-message ()
+  (logview--test-with-file "monolog/1.log" ()
+    (logview--locate-current-entry entry start
+      (logview-go-to-message-beginning)
+      (should (looking-at "Emergency message.$")))))
+
+(ert-deftest logview-test-monolog-submode-match-all-levels ()
+  (logview--test-with-file "monolog/1.log" ()
+    (logview--locate-current-entry entry start
+      (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 0))
+      (logview-next-entry)
+      (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 1))
+      (logview-next-entry)
+      (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 2))
+      (logview-next-entry)
+      (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 3))
+      (logview-next-entry)
+      (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 4))
+      (logview-next-entry)
+      (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 5))
+      (logview-next-entry)
+      (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 6))
+      (logview-next-entry)
+      (should (equal (logview--locate-current-entry entry nil 
(logview--entry-level entry)) 7)))))
diff --git a/test/monolog/1.log b/test/monolog/1.log
new file mode 100644
index 0000000000..10a7ae2e29
--- /dev/null
+++ b/test/monolog/1.log
@@ -0,0 +1,10 @@
+[2019-12-23 10:51:54] name[thread].EMERGENCY: Emergency message.
+[2019-12-23 10:51:55] name[thread].ALERT: Alert message.
+[2019-12-23 10:51:55] name[thread].CRITICAL: Critical message.
+[2019-12-23 10:51:56] name[thread].ERROR: Error message.
+[2019-12-23 10:51:56] name[thread].WARNING: Warning message.
+[2019-12-23 10:51:56] name[thread].NOTICE: Notice message.
+[2019-12-23 10:51:56] name[thread].INFO: Info message.
+[2019-12-23 10:51:56] name[thread].DEBUG: Debug message.
+[2019-12-23 10:51:56] name[thread].KITTENS: No such level defined by RFC 5424.
+[2019-12-23 10:51:56] name[thread].INFO: Info message after an invalid level.

Reply via email to