log4j 설정 (additivity)

log4j는 개발중에 로그를 찍을 수 있게 만들어 놓은 구현 체 입니다. 사실 로그 구현체는 상당히 많이 존재하지만 그 중 log4j와 jdk1.4 Logging API가 가장 널리 사용되고 있습니다.
오늘은 이 중 log4j의 설정에 대해서 설명하도록 하겠습니다.우선 설정파일은 xml, properties 형식이 허용됩니다. 설정파일의 위치는 따로 지정할 필요 없이 classpath에 위치하면 됩니다. 단, 파일의 이름이 log4j.xml 이나 log4j.properties여야 합니다. 만약 두개의 파일이 동시에 존재한다면 log4j.xml을 설정파일로 사용하게 됩니다.

log4j는 3개의 컴포넌트가 있습니다.  (여기서의 설명은 내가 생각하는 의미로 정확하지 않을 수 있습니다.)
Logger: 실제 로그를 찍는 구현체입니다. 
Appender: 로그 이벤트를 출력하는 채널을 결정. File, Console, GUI components, remote socket, JMS… 등등이 있다고 합니다. 
저는 File과 Console만 사용해 봤네요.
Layout: 로그 이벤트가 발생했을 때 로그가 쓰여지는 포맷입니다.

이 중 가장 중요하고 헷갈리는 Logger에 대해서 알아보겠습니다.Logger는 최상단에 root를 시작으로 계층구조를 갖습니다. (참고, root는 항상 존재하고 이름으로 접근할 수 없습니다.) 계층 구조 정보는 Logger의 이름으로 설정, 인식이 가능합니다. 
예를 들어서 “com.foo” 라는 이름의 Logger가 있습니다. 이 Logger는 “com.foo.bar”의 부모가 됩니다. 그럼 이 계층구조는 왜 존재할까요? 그것은 바로 로그 이벤트 발생시 전달을 하기 위함입니다. 자 아래 예를 들어 설명하겠습니다. 두 개의 Logger가 있습니다. 

com.foo (부모)     
    |     
    +–com.foo.bar (자식)

부모에서 로그 이벤트가 발생하면 부모의 Logger에서만 로그가 찍히게 됩니다. 물론 이벤트와 Logger.level에 따라 찍히지 않을 수도 있지만 우선 모두 찍히는 조건이라고 가정하고 설명하겠습니다.) 반면 자식 Logger에서 로그 이벤트가 발생하면 부모에게도 전달이 됩니다. 이 말은 자식 Logger에서 로그 찍고 부모 Logger에도 로그 찍는다는 겁니다.  이런 구조라서 모든 로그를 다 찍고 싶으시다면 root Logger를 이용해서 로그를 찍도록 합니다.  
위의 계층구조덕에 자식의 로그는 부모에서도 찍힐 수 밖에 없습니다. 그럼 부모쪽의 로그파일의 사이즈가 매우 커질 수 밖에 없고 원치않은 정보가 부모에서 찍히는 단점이 있습니다. 과연 이렇게 사용될 수 밖에 없는걸까요?
다행히도 additivity 라는 속성을 이용해서 위의 문제를 해결할 수 있습니다. additivity는 사전에 다음과 같이 설명되어 있습니다.
additivity:  1 부가적인, 덧셈의, 가법의   2 첨가물, 첨가제

무언가를 더한다는 의미입니다. 그럼 이제 어떤식으로 쓰이는지 보겠습니다.
역시 동일한 두개의 Logger가 있습니다. 

com.foo (부모)     
    |     
    +–com.foo.bar (자식)   <- additivity false 선언

위와같이 설정하면 자식의 로그 이벤트는 부모에게 전달되지 않습니다. 그럼 손자가 있을 경우는 어떻게 될까요?

com.foo (부모)     
    |
    +–com.foo.bar (자식)   <- additivity false 선언               
        |
        +–com.foo.bar.app(손자)

위와 같다면 손자의 로그 이벤트는 자식에게 전달이 됩니다. 하지만 부모에게는 전달되지 않습니다.  
간단히 말하면, 자식의 로그 이벤트는 부모가 전달 받는다. 자신의 이벤트 로그는 부모에게 전달한다. 단, additivity가 false로 설정되면 로그 이벤트는 부모에게 전달되지 않는다. 
이런 연유로 부모는 이벤트가 전달되지 않으니 로그를 찍을래야 찍을 수가 없습니다.additivity를 이용해 부모 자식간의 이벤트를 분리해 놓은 설정파일입니다.
#부모 logger 설정
log4j.logger.com.foo.bar=INFO, debug_log
log4j.appender.debug_log.Threshold=INFO
#자식 logger 설정
log4j.logger.com.foo.bar=INFO, trace_log
log4j.additivity.com.foo.bar.log=false# additivity=false 설정
만약 위에서 com.foo.bar에 additivity 설정이 true 혹은 안되어 있다면 com.foo에서도 자식 로그가 찍히게 됩니다.
자세한 설명을 하려니 복잡해지고 이해하기 힘들거 같습니다. 언제나 질문이나 피드백은 대 환영입니다.
좋은 하루 되세요!

은행에서 동전교환

자전거 출퇴근을 위해 한 동안 모아온 저금통을 뜯었다. 대략 500원짜리 5만원, 100원짜리 6만원 정도였다.

예전에 동전을 바꾸기 위해 몇 번 헛탕을 친 경험이 있어서 동전을 가져 가면서 안될수도 있다는 생각을 했었다.

처음 간 곳은 K 은행. 동전 교환기는 있었지만 계좌가 없으면 동전 교환이 안된다고 하였다. 계자는 있지만 계좌 번호나 카드번호가 없어서 포기~

두번째로 간 H 은행. 들어가자 마자 청원 경찰 느낌이 나는 분이 친절하게 안내해줬다. 다행히 이 곳은 계좌가 없더라도 바로 현금으로 내주는게 가능하다고 했다.

와후~

예전에 특정 요일, 특정 시간에만 가능하던 은행의 서비스와는 달랐지만 은행별로 서비스의 차이가 느껴지는 대목이었다. 동전교환 자체는 은행에 큰 이득이 없는 서비스 일 것이다. 하지만 장기적으로 봤을 때 서비스를 받는 고객이 느끼는 점은 크게 달라질 수 있는 요인이라고 생각한다.

앞으로 일을 하면서 고객의 입장을 좀 더 생각하며 일 할 수 있도록 노력해야 겠다.

Eclipse galileo + Tomcat 6.0 + Oracle 10g DBCP 연동 설정

오랜만에 JEE 공부할 필요가 생겨서 Eclipse galileo, Tomcat, Oracle 10g를 다운 받았다.

이번에 Tomcat과 Oracle 연동 설정하며 정리했던 사실을 공유하고자 포스팅을 한다.

검색을 해보면 관련된 포스팅이 상당히 많이 있는데, 오히려 많은 양의 정보가 나를 더 헷갈리게 했다.

이 포스팅으로 유사 설정을 하시는 분들이 나 처럼 뻘짓하지 않기를 바란다.

기본 환경은 다음과 같다.

Eclipse galileo, Tomcat 6.0, Oracle 10g, Eclipse Tomcat plugin…  이클립스에 톰캣 플러그인을 설치하는 과정은 생략하도록 하겠다. 모르는 사람은 검색 한번 해보면 쉽게 방법을 알 수 있을 것이다.

우선 위의 언급한 환경이 다 설치되어 있다는 가정하에 설명을 진행하겠다. (참고로 tomcat 6.0은 DBCP 라이브러리를 따로 추가할 필요가 없다. 단, ojdbc1.4.jar만 복사해서 $CATALINA_BASE/LIB 에 넣어주면 된다.)

위의 프로그램이 정상적으로 설치되어 있는 상태라면 중요한 것은 Configuration 파일들을 정리하기만 하면 된다.

수정 및 생성이 필요한 파일은 단 두개이다. web.xml, context.xml

우선 새로 작성한 context.xml을 생성 하겠다. Tomcat 홈페이지를 가보면 context에 관련된 문서가 있는데, 그 문서에 따르면 여러가지 방법으로 context를 정의할 수 있다. 그 중에서 선택했던 방법은 다음과 같다.

$CATALINA_BASE/conf/[enginename]/[hostname]/[context_path].xml

내 컴퓨터에서 위에 해당되는 위치는 다음과 같다.
(위의 의미를 잘 모르는 사람은 내 컴퓨터에서의 위치와 비교해서 보면 이해하기 편할 것 같다.)
C:\Tomcat_6.0\conf\Catalina\localhost/ROOT.xml

context.xml에서 context 태그 하단부에 다음을 추가했다.



여기서 중요한 부분은 저 Resource 태그에서 중요한 것은 첫 문자가 “R” 대문자여야 한다는 것, 만약 소문자로 하면
Cannot create JDBC driver of class ” for connect URL ‘null’ 
에러가 발생한다. 이 부분을 몰라서 한참 고생했기에 언급한다.

그리고 web.xml에서 추가한 부분은 다음과 같다.



이렇게 두 개가 끝이다. 여기까지 하면 DBCP를 사용해서 DB 연동작업 하는 것은 완료.

참고로 context.xml에서 파일 이름은(확장자를 제외한 부분)은 실제 context의 path를 의미한다.

Tomcat을 설치하면 기본적으로 context 폴더에 ROOT.xml이 존재한다. 이 ROOT는 tomcat에서 기본으로 path=”/”를 의미한다. 설정하려는 application의 path가 “/test”라면 context의 파일 이름이 test.xml이 되야 환경파일로 인식하고 로딩한다. 이 부분 또한 모르면 고생하기에 언급한다.

환경 설정에서 이렇게 고생을 할줄이야…ㅜ.ㅜ

I'm free to help you with it if you'd like.

A: I’ve got a full day today. I have to complete the market study for that proposal we need to submit by week’s end.

B: I’m free to help you with it if you’d like.

A: It’s ok. I’ve got all the data I need. I just need to do the analysis and write up the report.

B: Ok. Holler if you need me.

A: 나 오늘 정말 할일 많아요. 이번 주말까지 그 기획안에 대한 시장 조사서를 끝내야 하거든요.

B: 당신만 괜찮다면 제가 도와줄게요.

A: 괜찮아요. 필요한 데이터는 이미 갖고 있거든요. 데이터 분석하고 리포트만 쓰면 되요.

B: 그래요. 제가 필요하면 저를 부르세요.

운전면허증 갱신

2001년 경에 야매(?)를 이용해서 저렴한 가격으로 운전면허를 취득하고 2008년 까지 운전을 안하다가 최근에 하기 시작했다.

실제 운전 기간은 1년여도 되지 않는데 어찌됐든 난 8년 이상된 운전자고 그리하여 갱신을 해야 했다. 마침 오늘 쉬는 날이라서 삼성역 부근에 있는 운전면허관리공단에 방문했다.

평일임에도 불구하고 사람들이 많이 붐볐다. 갱신을 위한 인지(10,000원)를 사고 사진을 두 장 붙이고 접수를 하려고 순서표를 뽑고 기다렸다. 무려 80명 정도의 사람을 기다려야 했는데, 내 번호가 다가와서 내가 자리에 일어나자 접수대에 있는 접수원이 내 표를 보고 우선 신체검사를 받고 와야 한다는 것이었다. 젠장~~~ 왜 그런 순서 같은것은 안내로 없는건지…

어쨋든 신체검사를 받으러 다른 건물 1층으로 이동했다. 이 곳에서 나는 말로만 듣던 ‘눈가리고 아웅’ 식의 신체검사를 받았다. 내 발과 손이 제대로 움직이는지 확인 하는데, 아니 나를 포함한 20명 정도의 사람을 확인하는데 약 1분 걸린다. 방법은 심플하다.
감독관: “제자리에 앉아 주시구요, 손으로 주먹 줬다 펴 보세요”

그리고 나서는 시력 검사, 대충 0.8 정도의 시력이 나오면 무리없이 통과, 그리고 색맹검사를 하고 나면 끝.

신체검사 시작을 기다리는데 5분, 손, 발, 시력 등 갱신을 하는데 필요한 검사를 하는데 1분 30초 걸린것 같다.

이 절차가 끝나면 접수서에 도장을 마구 찍어주는데 이 걸 접수원에게 전해주면 5분 정도후에 새로운 운전면허증이 발급된다.

쩝, 굉장히 형식적인….

Database Lock을 예방하는 자세

서비스 관련 코드를 개발하는 일에 DB가 빠질리 없다. 정말 독특한 경우에는 빠질 수도 있겠지만 내 경우에는 그런 적이 없는 것 같다.

각설하고, 오늘의 삽질을 소개하겠다.

개발하는 솔루션에 Legacy 연동을 위해서 static method -> Servlet(XML-RPC) -> Socket 을 사용하고 있었다. 나름 완벽한 로직을 만들고자 Socket쪽에 Response를 일정시간 동안 하지 않도록 수정했다.
 이렇게 했더니 동시에 Legacy 연동 요청이 왔을 경우 기존 요청이 완료된 후에 해당 요청이 수행되는 것이었다.

나름 생각해서 이 것은 XML-RPC 쪽의 문제가 아닐까란 추론을 하고 금요일 부터 오늘까지 계속 디버깅을 해봤다. 디버깅은 가장 친숙한 Log를 남기는 것으로… 언제 한번 Eclipse 를 이용한 debuging 방식에 대해서 공부해 봐야겠다.

나의 허접함을 들어냈던 오늘 문제의 원인은… 바로 Database Lock 이었다. table에 download 라는 필드가 있는데 버그가 났던 method가 호출되면 download 필드를 update하는 부분이 있다. 그런데 이 부분이 method의 초반 부분에 있고 transaction의 commit 혹은 rollback은 가장 끝 부분에 있는 것이었다.

첫 번째 요청이 download 필드를 update하고 transaction이 마무리 되는 부분에 도달하기 전에 두 번째 요청이 들어온다면 첫 번째 요청의 transaction이 마무리 될 때까지 기다리게 되는 것이었다. 헌데 이제까지 본 문제가 발견되지 않았던 것은 response의 응답시간이 늦는 경우의 테스트가 되지 않았던 이유도 있고, 같은 record의 download 필드를 update 하는 것이 제대로 테스트 되지 않았기 때문이다.

그래서 이번 문제의 해결 방안은 database의 lock을 발생 시킬 수 있는 update 관련 명령어는 transaction의 끝 부분에 옮기는 것으로 일단락 하였다.

Multithread가 되면 lock에서 자유로울 것이라 생각했지만 너무 짧은 생각. sql 중 update의 사용은 더욱 조심 스럽게 해야겠다.

처음 글

항상 시작할 때에는 맘의 무게나 마음 가짐은 대단하다.

그리고는 시간이 흐르면 언제 그랬냐는 듯 그 마음이 옅어지고… 그러다가 관심이 없어진다.

블로그를 만든 목적을 잊지 말자.

1. 다양한 공부 거리, 주로 업무중에 터득하게 되는 노하우 혹은 팁이 될 것이다. 이런 정보는 정말 간단하지만 나와 같은 문제를 직면한 사람에게는 아주 중요한 정보를 제공할 수 있을 것이다.

2. 가능한 자주 글을 올리자. 글을 올리며 나의 생각을 다시 한번 정리하고 이는 나의 든든한 자산이 될 것이다.

덧 붙이기.
우선 닉네임부터 지어야 하는데, 쉽지 않다. 시간을 갖고 생각해서 맘에 드는 걸로 멋지게 하나 만들어 내자.