Semantic Logging 이란
MS patterns & practices 에 올라온 글 중에 Embracing Semantic Logging 이라는 글을 보았다.EventSource 라는 logging class 을 의 wrapper class 인 Semantic Logging Aplication Block 을 소개하는 글이었다. 그 글을 읽다보니 semantic logging 이 뭔지 궁금하였다.
semanctic logging 을 하는 것이라고 하는데, ref. 1 을 읽어보면 뭐, 그리 어려운 것은 아니고, 말 그대로 구조를 갖춘 로그를 얘기하는 듯 하다. 그래서 semantic logging / structured logging / strongly-typed logging /schematized logging 등 다양하게 불리는 듯 하다. 이 logging 의 차이점을 보여주자면,
일반적으로
printf("log: %s %s", tag, time)이런 간단한 log 를 찍게 되는데, 한 두 개 찍는 것에는 큰 문제가 없다. 물론 많이 찍는 것도 문제는 없다. 하지만 이 녀석이 너무 많아지면 이것을 확인하는 주체가 사람인데, 보기가 너무 힘들다. text editor 로 불러다가 ctrl+f 로 열심히 뒤져봐야 할 것이다. 그래서 이것을 보기 쉽게 해주기 위해 이 log 들을 parsing 해서 특정조건에 맞게 정렬 해 준 program을 작성할 수 있을 것이다.
or
System.out.println("log here");
문제는 이 때 이 프로그램을 짜려면 조금 힘들어 진다. 물론 regular expression 등의 string parser 를 이용하면 크게 어렵지 않지만, 그래도 코드가 아무래도 길어지고, parsing 의 속도는 더딜 수 밖에 없다.
그래서 이것을 구별하기 위해 애쓰지 말고, 구별해 놓은 상태로 log 찍는 법을 일정 틀 안에 놓은 것이다. 이것을 class 로 구현을 한다면 id 나 tag 에 따라서 다른 함수를 호출하는 것이다.
손쉽게 Android 의 Log class 를 확인 해 보자.
Log.d(tag, "message");이런 식으로 log 를 찍는데 이렇게 해서 log 를 특정 id(tag, priority 등) 별로 구분 하기 쉽게 하는 것이다. 그러면 나중에 log 분석 tool 등과 관련된 프로그래밍이 수월해 진다. ref. 1 을 보면 쉽게 짐작할 수 있다.
Log.i(tag, "message");
Log class
그런 의미에서 android 의 Log class 를 살펴 보는 것도 좋은 공부가 될 듯 하다. 아래는 Log class 의 함수호출 stack 이라고 보면 되겠다. 자세한 사항은 ref. 2를 참고하도록 하자.- Log.i()
- -> Log.println_native()
- -> android_util_Log_println_native()
- -> __android_log_buf_write()
- -> write_to_log()
- -> __write_to_log_kernel()
- -> log_writev()
- -> writev -> logger_aio_write()
잡담
개인적으로 아래 code 가 신선했다. 그래서 옮겨 놓는다.static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr); static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init; static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) { #ifdef HAVE_PTHREADS pthread_mutex_lock(&log_init_lock); #endif if (write_to_log == __write_to_log_init) { log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY); log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY); log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY); log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY); write_to_log = __write_to_log_kernel; if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 || log_fds[LOG_ID_EVENTS] < 0) { log_close(log_fds[LOG_ID_MAIN]); log_close(log_fds[LOG_ID_RADIO]); log_close(log_fds[LOG_ID_EVENTS]); log_fds[LOG_ID_MAIN] = -1; log_fds[LOG_ID_RADIO] = -1; log_fds[LOG_ID_EVENTS] = -1; write_to_log = __write_to_log_null; } if (log_fds[LOG_ID_SYSTEM] < 0) { log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN]; } } #ifdef HAVE_PTHREADS pthread_mutex_unlock(&log_init_lock); #endif return write_to_log(log_id, vec, nr); }
References
- http://gregoryszorc.com/blog/category/logging/
- Android Log 분석, 2012년 1월, 땅뚱 블로그
댓글 없음:
댓글 쓰기