Лог работы
Иногда становится необходимым просмотреть последовательность и затраты времени на выполнение каких-либо команд, функций и т.п. Здесь расскажу о том, как это у меня организовано, какие коды используются.
Первый вопрос - это куда записывать лог-файл. Я принял, что лог должен записываться в определенный каталог, расположенный либо в %temp% текущего пользователя, либо в %appdata%. Оба решения имеют свои плюсы и минусы.
При записи в %temp% вычистить лог очень легко. Это плюс. Удалить логи слишком легко - и это минус.
При записи в %appdata% надо предусмотреть автоматическое удаление слишком разросшихся файлов. Здесь этот вопрос не освещаю (просто чтобы не запутать лишними подробностями ;))
Запись лога на сервер я всерьез не рассматриваю,- там слишком много может быть ограничений. А механизм должен работать всегда.
Второй вопрос - это имя лог-файла. В принципе, тут никаких ограничений, но для примера примем, что имя лог-файла должно формироваться по принципу <ДоменКомпьютера>-<ИмяКомпьютера>-<ИмяПользователя>.log. Если объем файла превышает 2Mb, старый файл копируется с указанием даты, и создается новый.
Далее нам гарантированно понадобятся функции показа текущего лога, функции записи в лог нужной информации, а также - внимание! - еще один "переключатель". Последняя функция позволит нам с легкостью переключать режим ведения лога. Например, при разработке, тестировании или при непонятных ситуациях у пользователя можно включить режим лога, а потом уже и анализировать лог.
Получим имя лог-файла:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | (defun _kpblc-get-file-log (/ path file handle) ;| * Возвращает имя файла лога. Если файл существует и его размер больше 2Mb, * то файл автоматически копируется и пересоздается |; (setq path (_kpblc-dir-create (strcat (vl-string-right-trim "\" (getenv "appdata")) "\\kpblc\"))) (cond ((not (findfile (setq file (strcat path (getenv "userdomain") "-" (getenv "computername") "-" (getenv "username") ".log" ) ;_ end of strcat ) ;_ end of setq ) ;_ end of findfile ) ;_ end of not file ) ((and (findfile file) (> (vl-file-size file) (* 2 (expt 2 20))) ) ;_ end of and (vl-file-copy file (strcat (_kpblc-dir-path-no-splash (vl-filename-directory file)) "\" (vl-filename-base file) "_" (rtos (getvar "cdate") 2 6) ) ;_ end of strcat ) ;_ end of vl-file-copy (setq handle (open file "w")) (close handle) file ) (t file) ) ;_ end of cond ) ;_ end of defun |
Потребуется одна служебная функция:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | (defun _kpblc-dir-create (path / tmp) ;| * Гарантированное создание каталога. * Параметры вызова: path создаваемый каталог |; (cond ((vl-file-directory-p path) path) ((setq tmp (_kpblc-dir-create (vl-filename-directory path))) (vl-mkdir (strcat tmp "\" (vl-filename-base path) (cond ((vl-filename-extension path)) (t "") ) ;_ end of cond ) ;_ end of strcat ) ;_ end of vl-mkdir (if (vl-file-directory-p path) path ) ;_ end of if ) ) ;_ end of cond ) ;_ end of defun |
Далее напишем тот самый "переключатель" (функция записи лога будет ссылаться на его данные):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | (defun _kpblc-log-toggle (param) ;| * Функция включения или отключения процедуры лога * Параметры вызова: param включить лог (t) или отключить (nil) |; (vl-bb-set '*kpblc-settings* (_kpblc-list-add-or-subst (vl-bb-ref '*kpblc-settings*) "log" param) ) ;_ end of vl-bb-set (princ (strcat "\nЛог " (if param "запущен" "остановлен" ) ;_ end of if ) ;_ end of strcat ) ;_ end of princ (princ) ) ;_ end of defun |
Что здесь происходит? Указанная настройка (вести лог или нет) записывается во внедокументную перемнную *kpblc-settings*. Т.е. указанная настройка будет доступна во всех документах текущей сессии AutoCAD. Такое решение было обусловлено тем, что иногда при открытии какого-либо файла мне уже надо было вести лог выполняющихся действий. Но это мое решение...
Точно так же потребуется одна служебная функция замены элемента в списке:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | (defun _kpblc-list-add-or-subst (lst key value) ;| * Производит замену или дополнение элемента списка новым * Параметры вызова: lst обрабатываемый список key ключ value устанавливаемое значение |; (if (not value) (vl-remove-if (function (lambda (x) (= (car x) key))) lst) (if (cdr (assoc key lst)) (subst (cons key value) (assoc key lst) lst) (cons (cons key value) (vl-remove-if (function (lambda (x) (= (car x) key) ) ;_ end of lambda ) ;_ end of function lst ) ;_ end of vl-remove-if ) ;_ end of cons ) ;_ end of if ) ;_ end of if ) ;_ end of defun |
Теперь можно приступать уже собственно к разработке функции записи в лог какой-либо информации. Вопрос фактически один: а что мы собираемся вообще записывать?
- Нам может понадобиться время (с точностью, например, до секунд). А может и не понадобиться
- Точно так же может понадобиться указание имени выполняемой lisp-функции
- В некоторых случаях лог должен записываться невзирая на установленные "переключателем" настройки
- Может понадобиться дополнительное пояснение
- В обязательном варианте записываем полное имя текущего документа. Если документ еще не сохранялся, то в качестве имени пишем "Файл не сохранен"
Получается нечто типа:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | (defun _kpblc-log (lst / handle sep) ;| * выполняет запись сообщения в лог * Параметр вызова: lst список дополнительных параметров '(("time" . <Указывать время>) ("cmd" . <Указывается имя функции>) ("req" . <Лог выполнять в любом случае>) ("msg" . <Дополнительное пояснение>) ) |; (if (or (cdr (assoc "req" lst)) (cdr (assoc "log" (vl-bb-ref '*kpblc-settings*))) ) ;_ end of or (progn (setq sep "\t" handle (open (_kpblc-get-file-log) "a") ) ;_ end of setq (write-line (strcat (if (= (vla-get-fullname (vla-get-activedocument (vlax-get-acad-object))) "") "Файл не сохранен" (strcat (vl-string-right-trim "\" (getvar "dwgprefix")) "\" (getvar "dwgname")) ) ;_ end of if sep (cond ((cdr (assoc "cmd" lst))) (t "Имя lisp не указано") ) ;_ end of cond sep (if (cdr (assoc "time" lst)) (_kpblc-conv-date-to-string) "" ) ;_ end of if (if (cdr (assoc "msg" lst)) (strcat sep (cdr (assoc "msg" lst))) "" ) ;_ end of if ) ;_ end of strcat handle ) ;_ end of write-line (close handle) ) ;_ end of progn ) ;_ end of if ) ;_ end of defun |
Потребуется функция преобразования текущей даты в формат "ГГГГ-ММ-ДД чч:мм:сс":
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | (defun _kpblc-conv-date-to-string (/ date sdate stime) ;| * Преобразовывает текущую дату и время в строковое представление |; (setq date (getvar "cdate") sdate (fix date) stime (- date sdate) sdate (itoa sdate) stime (itoa (fix (* stime 1e6))) ) ;_ end of setq (while (< (strlen stime) 6) (setq stime (strcat "0" stime)) ) ;_ end of while (strcat (substr sdate 1 4) "-" (substr sdate 5 2) "-" (substr sdate 7) " " (substr stime 1 2) ":" (substr stime 3 2) ":" (substr stime 5) ) ;_ end of strcat ) ;_ end of defun |
Теперь осталось только нарисовать "показ" лога. Ну, тут уже совсем просто:
1 2 3 4 5 6 7 8 9 10 11 12 | (defun _kpblc-log-show (/ file) ;| * Выводит окно лога в отдельном приложении (блокнот) |; (if (setq file (findfile (_kpblc-get-file-log))) (startapp "notepad.exe" (_kpblc-get-file-log) ) ;_ end of startapp (alert "Файл лога не обнаружен!") ) ;_ end of if (princ) ) ;_ end of defun |
Немного пояснений. В качестве разделителя данных в лог-файле выбран символ табуляции: это позволит, сменив расширение на csv, выполнить открытие лога в Excel / LibreOffice / etc и выполнить практически любые действия.
В качестве примера использования функций:
1 2 3 4 5 6 7 8 9 10 11 | (defun test-log () (_kpblc-log '(("req" . t) ("time" . t) ("cmd" . "test"))) (_kpblc-log '(("req" . t) ("time" . t) ("cmd" . "test") ("msg" . "Проверочное сообщение"))) (entmakex (list (cons 0 "LINE") (cons 10 '(0. 0. 0.)) (cons 11 '(10. 10. 0.)) ) ;_ end of list ) ;_ end of entmakex (_kpblc-log '(("time" . t) ("cmd" . "test") ("msg" . "Необязательное сообщение"))) (princ) ) ;_ end of defun |
В логе будет нечто типа:
Файл не сохранен test 2015-11-26 16:44:44
Файл не сохранен test 2015-11-26 16:44:44 Проверочное сообщение
Переключим выполнение лога:
1 | (_kpblc-log-toggle t) |
И снова вызовем (test-log):
Файл не сохранен test 2015-11-26 16:44:44
Файл не сохранен test 2015-11-26 16:44:44 Проверочное сообщение
Файл не сохранен test 2015-11-26 16:51:44
Файл не сохранен test 2015-11-26 16:51:44 Проверочное сообщение
Файл не сохранен test 2015-11-26 16:51:44 Необязательное сообщение
Как видно, добавилось "необязательное" сообщение.
Все коды, кроме "тестировочного", можно забрать здесь
Во первых блогодарю.
По поводу _kpblc-conv-date-to-string
Я нашел такую
(menucmd "M=$(edtime,$(getvar,date),DDDD\",\" D MONTH YYYY hh:mm:ss.msec)")
ПС Есть несколько вопросов.
Merci
Можно и так. Мало того, я лично знаю человека, который только так и работает
P.S. Вопросы по статьям - добро пожаловать в соответствующие записи. Если вопросы по другим темам - то лучше на форумах (adn-cis.org, dwg.ru, autodesk.com). Я с ними соперничать точно не стану
Мне нравится что вы делаете. Я пишу сам и самоучка в Alisp. Хочу показать что я сделал поправить или поделится мнением, дать несколько ориентиров чтоб идти дальше. Я каждый день порожаюсь мощью языка, говорю людям но ...Как можем связатся? Стирите потом сообщ
На странице http://autolisp.ru/about/ есть ссылка на лисп-код, который покажет мой e-mail.