Лог работы

Иногда становится необходимым просмотреть последовательность и затраты времени на выполнение каких-либо команд, функций и т.п. Здесь расскажу о том, как это у меня организовано, какие коды используются.

Первый вопрос - это куда записывать лог-файл. Я принял, что лог должен записываться в определенный каталог, расположенный либо в %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

Теперь можно приступать уже собственно к разработке функции записи в лог какой-либо информации. Вопрос фактически один: а что мы собираемся вообще записывать?

  1. Нам может понадобиться время (с точностью, например, до секунд). А может и не понадобиться
  2. Точно так же может понадобиться указание имени выполняемой lisp-функции
  3. В некоторых случаях лог должен записываться невзирая на установленные "переключателем" настройки
  4. Может понадобиться дополнительное пояснение
  5. В обязательном варианте записываем полное имя текущего документа. Если документ еще не сохранялся, то в качестве имени пишем "Файл не сохранен"

Получается нечто типа:

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 Необязательное сообщение

Как видно, добавилось "необязательное" сообщение.

Все коды, кроме "тестировочного", можно забрать здесь

Размещено в Код LISP, Новости, Функции LISP · Метки: ,



Комментарии

Есть 4 коммент. к “Лог работы”
  1. CCCP пишет:

    Во первых блогодарю.
    По поводу _kpblc-conv-date-to-string
    Я нашел такую
    (menucmd "M=$(edtime,$(getvar,date),DDDD\",\" D MONTH YYYY hh:mm:ss.msec)")
    ПС Есть несколько вопросов.
    Merci

  2. Кулик Алексей aka kpblc пишет:

    Можно и так. Мало того, я лично знаю человека, который только так и работает :)
    P.S. Вопросы по статьям - добро пожаловать в соответствующие записи. Если вопросы по другим темам - то лучше на форумах (adn-cis.org, dwg.ru, autodesk.com). Я с ними соперничать точно не стану :)

  3. CCCP пишет:

    Мне нравится что вы делаете. Я пишу сам и самоучка в Alisp. Хочу показать что я сделал поправить или поделится мнением, дать несколько ориентиров чтоб идти дальше. Я каждый день порожаюсь мощью языка, говорю людям но ...Как можем связатся? Стирите потом сообщ

  4. Кулик Алексей aka kpblc пишет:

    На странице http://autolisp.ru/about/ есть ссылка на лисп-код, который покажет мой e-mail.

Поделитесь своим мнением


Я не робот.