├── huskie-tests.el ├── README.creole └── huskie.el /huskie-tests.el: -------------------------------------------------------------------------------- 1 | ;;; Tests for huskie 2 | 3 | (require 'ert) 4 | (require 'huskie) 5 | 6 | (ert-deftest huskie/make-log-process () 7 | "Test the filename safety." 8 | (should (huskie/make-log-process "testlog" "/tmp/filename")) 9 | (should-error (huskie/make-log-process 10 | "testlog" "/tmp/filename ; rm -rf /tmp"))) 11 | 12 | 13 | ;;; huskie-tests.el ends here 14 | -------------------------------------------------------------------------------- /README.creole: -------------------------------------------------------------------------------- 1 | = Huskie - the powerful logger = 2 | 3 | Make logging through processes. 4 | 5 | == Why Huskie?? == 6 | 7 | Named after my trusty Husqavana chainsaw. How I love it. 8 | 9 | == Usage == 10 | 11 | {{{ 12 | (huskie-log "something" "logger-name") 13 | }}} 14 | 15 | will send "something" to the "logger-name" which will be 16 | automatically mapped to a file in "/tmp/logger-name" 17 | 18 | The automatic file mapping is done with 19 | `huskie-log-default-directory' which is a variable you can let-bind 20 | or simply change. 21 | 22 | {{{ 23 | (let ((huskie-log-default-directory "/home/nictest")) 24 | (hukie-log "just a test" "my-log")) 25 | }}} 26 | 27 | will send "just a test" to the log process "my-log" and create a 28 | file "/home/nictest/my-log" 29 | 30 | == Log Files == 31 | 32 | The mapping between filenames and lognames can be defined: 33 | 34 | {{{ 35 | (huskie-bind-logname->filename "nictest" "/tmp/my-log") 36 | (huskie-log "test100!" "nictest") 37 | }}} 38 | 39 | will send "test100!" to the file "/tmp/my-log" though a logging 40 | process called "nictest" will be created. 41 | 42 | The filename used MUST be a file, it is specifically checked for 43 | fileness and huskie fails if it's not. 44 | 45 | However, huskie does NOT check that the file is under any sane root; 46 | indeed, it cannot do so because you might want to save log files in 47 | all sorts of odd places. 48 | 49 | //I am very interested to hear what people think about this so do 50 | create an issue 51 | on [[http://github.com/nicferrier/emacs-huskie|the GitHub]] if you 52 | have a viewpoint about this.// 53 | 54 | 55 | == Processes == 56 | 57 | All the logging is done through async processes. A default process 58 | is used unless something specific exists for the logname. Setting a 59 | script can be done with `huskie-set-script'. 60 | 61 | The script MUST include a single %s to accept the filename. Failure 62 | to do so will result in an error. 63 | 64 | The script MUST be a shell script. 65 | 66 | {{{ 67 | (huskie-set-script 68 | "nictest-log" 69 | "while read line; do echo $line > %s ; done") 70 | (huskie-log "test 200" "nictest-log") 71 | }}} 72 | 73 | will send "test 200" through "nictest" via the syslog logger 74 | program. 75 | 76 | You can avoid the use of the filename through shell tricks: 77 | 78 | {{{ 79 | (huskie-set-script 80 | "nictest-log" 81 | "while read line; do logger -t my-log $line ; done # %s") 82 | (huskie-log "test 200" "nictest-log") 83 | }}} 84 | 85 | this will send the logging through the system logger, the filename is 86 | just ignored. 87 | 88 | The shell script could totally alter the filename passed into it. 89 | 90 | Here's an example where all the things that can be adjusted, are: 91 | 92 | {{{ 93 | (huskie-set-script 94 | "test-log" 95 | "while read line; do echo $line > %s ; done") 96 | (huskie-bind-logname->filename "test-log" "/tmp/my-log") 97 | (huskie-log "test 200" "test-log") 98 | }}} 99 | 100 | this causes all lines to go through the script, which is simple (but 101 | could of course be quite complicated) but causes the file created to 102 | be {{{/tmp/my-log}}}. 103 | 104 | == Tips == 105 | 106 | Using the shell form: 107 | 108 | {{{ 109 | while read line ; do ... ; done 110 | }}} 111 | 112 | is an excellent way of ensuring you have lines going through 113 | loggers. This is why huskie does it this way. Other solutions are 114 | possible of course, but this is probably the best. 115 | 116 | Log scripts to create dates and such are likely good candidates for 117 | the shell script. 118 | 119 | 120 | == Warnings == 121 | 122 | Deriving log file destinations from the log text itself is a **VERY BAD** 123 | idea. Huskie makes no attempt to thwart this. If you do it you are a 124 | fool. 125 | -------------------------------------------------------------------------------- /huskie.el: -------------------------------------------------------------------------------- 1 | ;;; huskie.el --- chainsaw powered logging 2 | 3 | ;; Copyright (C) 2012 Nic Ferrier 4 | 5 | ;; Author: Nic Ferrier 6 | ;; Keywords: lisp, processes 7 | ;; Version: 0.0.3 8 | ;; URL: http://github.com/nicferrier/emacs-huskie 9 | ;; Package-Requires: ((anaphora "0.0.6")) 10 | 11 | ;; This program is free software; you can redistribute it and/or modify 12 | ;; it under the terms of the GNU General Public License as published by 13 | ;; the Free Software Foundation, either version 3 of the License, or 14 | ;; (at your option) any later version. 15 | 16 | ;; This program is distributed in the hope that it will be useful, 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | ;; GNU General Public License for more details. 20 | 21 | ;; You should have received a copy of the GNU General Public License 22 | ;; along with this program. If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; Make logging through processes. 27 | 28 | ;; Named after my trusty Huskavana chainsaw. How I love it. 29 | 30 | ;; Usage: 31 | ;; 32 | ;; (huskie-log "something" "logger-name") 33 | ;; 34 | ;; will send "something" to the "logger-name" which will be 35 | ;; automatically mapped to a file in "/tmp/logger-name" 36 | ;; 37 | ;; The automatic file mapping is done with 38 | ;; `huskie-log-default-directory' which is a variable you can let-bind 39 | ;; or simply change. 40 | ;; 41 | ;; (let ((huskie-log-default-directory "/home/nictest")) 42 | ;; (hukie-log "just a test" "my-log")) 43 | ;; 44 | ;; will send "just a test" to the log process "my-log" and create a 45 | ;; file "/home/nictest/my-log" 46 | ;; 47 | ;; The mapping between filenames and lognames can be defined: 48 | ;; 49 | ;; (huskie-bind-logname->filename "nictest" "/tmp/my-log") 50 | ;; (huskie-log "test100!" "nictest") 51 | ;; 52 | ;; will send "test100!" to the file "/tmp/my-log" though a logging 53 | ;; process called "nictest" will be created. 54 | ;; 55 | ;; All the logging is done through async processes. A default process 56 | ;; is used unless something specific exists for the logname. Setting a 57 | ;; script can be done with `huskie-set-script'. 58 | ;; 59 | ;; The script MUST include a single %s to accept the filename. Failure 60 | ;; to do so will result in an error. 61 | ;; 62 | ;; The script MUST be a shell script. 63 | ;; 64 | ;; (huskie-set-script 65 | ;; "nictest" 66 | ;; "while read line; do logger -f %s $line ; done") 67 | ;; (huskie-log "test 200" "nictest") 68 | ;; 69 | ;; will send "test 200" through "nictest" via the syslog logger 70 | ;; program. 71 | 72 | 73 | ;;; Code: 74 | 75 | (require 'anaphora) 76 | 77 | (defconst huskie/log-default-script 78 | "while read line ; do echo $line; echo $line >> %s ; done" 79 | "The default script for handling logging.") 80 | 81 | (defconst huskie/log-script-map 82 | (make-hash-table :test 'equal) 83 | "Map of lognames to scripts used for logging. 84 | 85 | The script should have a single %s in it which should point to 86 | any filename.") 87 | 88 | (defconst huskie/logname-file-map 89 | (make-hash-table :test 'equal) 90 | "Map of lognames to filenames. 91 | 92 | If you want a logname to map to a specific filename put something 93 | in this map via `huskie-bind-logname->filename'.") 94 | 95 | (defvar huskie-log-default-directory 96 | "/tmp" 97 | "The default directory where log files go.") 98 | 99 | (defun huskie-bind-logname->filename (logname filename) 100 | "Bind LOGNAME to FILENAME so we use that file when we log." 101 | (puthash logname filename huskie/logname-file-map)) 102 | 103 | (defun huskie-set-script (logname shell) 104 | "Specify that SHELL is used to log LOGNAME. 105 | 106 | SHELL MUST include a single %s to accept the filename. Failure 107 | to do so will result in an error. 108 | 109 | The filename passed to the %s WILL be checked to test for 110 | filenameness and NOT allow espcaping to shell." 111 | ;; TODO implement the filename checking of %s in make-log-process 112 | (puthash logname shell huskie/log-script-map)) 113 | 114 | (defun huskie/logname->proc-name (logname) 115 | "Make a proc name from a LOGNAME." 116 | (format "*log-%s*" logname)) 117 | 118 | (defun huskie/make-log-process (logname &optional filename) 119 | "Make a log process logging through LOGNAME script. 120 | 121 | Optionally use FILENAME as the destination. If there is no 122 | FILENAME then just derive one through LOGNAME. 123 | 124 | The script for logging is either LOGNAME specific via a lookup in 125 | `huskie/log-script-map' or the default log script 126 | `huskie/log-default-script'." 127 | (let* ((file 128 | (or filename 129 | (concat 130 | (file-name-as-directory huskie-log-default-directory) 131 | logname))) 132 | ;; TODO we MUST check `file' is a filename and not: 133 | ;; 134 | ;; /tmp/blah ; rm -rf / 135 | (log-name (huskie/logname->proc-name logname)) 136 | (buf-name (concat " " log-name)) 137 | (log-script 138 | (or (gethash logname huskie/log-script-map) 139 | huskie/log-default-script))) 140 | ;; Test the file is a filename 141 | (assert 142 | (equal file (shell-quote-argument file)) t 143 | nil "file %s is unsafe" file) 144 | (start-process-shell-command 145 | log-name (get-buffer-create buf-name) 146 | (format log-script filename)))) 147 | 148 | (defun huskie-log (text logname) 149 | "Send TEXT to LOGNAME. 150 | 151 | If LOGNAME does not have an existing process it is created via 152 | `huskie/make-log-process'." 153 | (let ((proc 154 | (or 155 | (get-process (huskie/logname->proc-name logname)) 156 | (huskie/make-log-process 157 | logname 158 | (let ((found-log 159 | (gethash logname huskie/logname-file-map))) 160 | (when found-log found-log)))))) 161 | (process-send-string proc (concat text "\n")))) 162 | 163 | (provide 'huskie) 164 | 165 | ;;; huskie.el ends here 166 | --------------------------------------------------------------------------------