기본사용법

대부분의 프로그래밍 언어는 여러 모듈과 라이브러리를 관리하기 위한 시스템을 가지고 있다. PHP는 PEAR(PHP Extension and Application Repository)라는 시스템을 가지고 있는데, 현재는 컴포져(Composer)에 밀려나는 중이다. 모던 PHP(Modern PHP)를 위해서라도 컴포져를 쓰는 것이 더 좋겠지만, 때로 아직은 PEAR를 써야 할 일이 종종 있다. 물론 이 경우라도 컴포져를 통해서 PEAR를 사용하는 것을 적극 권장한다. 컴포져를 이용해 PEAR를 사용하는 방법은 컴포져 설명서에 자세히 나와있다.

PHP를 설치하면 기본적으로 설치되는 PEAR 패키지가 몇개 있는데 Log도 그 중 하나다. 배포판에 따라 설치되지 않는 경우도 있지만, sudo pear install Log 명령을 통해서 간단히 설치 가능한다. 하지만 현재 Monolog가 쓰이는 경우가 더 많으므로, 새로운 프로젝트라면 그것을 쓰는 것을 더 추천하고 싶다.

예제를 통해서 Log 패키지 사용법을 하나씩 살펴보자.

1
2
3
4
5
6
7
<?php

require_once 'Log.php';

$logger = Log::factory('console', '', 'foobar');

$logger->log('Hello');
1
require_once 'Log.php';

Log 패키지를 사용하기 위해서는 Log.php를 읽어들여야 하는데, PEAR를 통해서 설치했다면 보통 include_path로 잡혀있기 때문에 경로 없이 파일만 지정하면 된다. 컴포져를 통해서 설치했다면 vendor/autoload.php를 로드하면 된다.

1
$logger = Log::factory('console', '', 'foobar');

Log 인스턴스를 하나 생성한다. 여기서는 Log::factory를 이용했다. 또 다른 방법으로 singleton 메소를 사용 할 수도 있는데, factory는 일반적으로 Log 인스턴스를 여럿 생성하기 위해 사용하고, singleton은 오직 하나의 Log 인스턴스만 생성하고 싶을 때 사용한다.

1
Log::factory($handler, $name, $ident, $conf, $maxLevel);

첫번째 매개변수 console은 화면에 로그 메시지를 출력하는 핸들러 생성을 의미한다. 두번째는 로그 리소스의 이름으로 기본값은 빈 문자열이다. 여기서는 기본값을 그대로 사용했다. 세번째는 로그 파일 내에 기록되는 identification string으로 같은 로그 파일 내에 여러 종류의 로그 메시지들이 기록될 때 서로 구분하기 위해 사용하는 고유한 문자열이다. 네번째와 다섯번째는 핸들러 설정을 위한 배열과 기록 할 로그 레벨을 정하기 위한 값인데, 생략하면 기본값을 사용한다.

1
$logger->log('Hello');

Log 인스턴스의 log 메소드를 통해서 로그 메시지를 기록한다. 두번째 메소드로 로그 레벨을 지정 할 수 있는데, 생략 할 경우 기본값인 PEAR_LOG_INFO를 로그 레벨로 사용한다.

singleton 메소드를 통해 Log 인스턴스를 생성하는 방법은 factory 메소드와 동일하지만, 둘의 차이는 singleton 경우는 여러번 인스턴스를 생성하더라도 오직 하나의 인스턴스를 생성한다는 점이다. 보통의 경우라면 factory 보다 singleton이 더 적절하다.

1
$logger = Log::singleton('file', 'foobar.log', 'foobar');

singleton 메소드의 사용법은 factory 메소드와 동일하다. 다만, 여기서는 로그 핸들러를 console이 아닌 file을 사용했다. file 로그 핸들러를 사용하면 메시지를 텍스트 파일로 저장한다. 파일로 저장하기 때문에 두번째 매개변수에 로그 파일명이 들어간다.

로그 레벨

로그 메시지에는 로그 레벨이란 것이 있는데, 대부분의 유닉스 계열의 로그 시스템에서 거의 동일하게 사용한다. Log에서도 마찬가지로 동일한 로그 레벨을 사용 중이고, Monolog, PSR-3, syslog를 사용한다고 해도 이 부분은 거의 같다.

Log 사용자 문서에 나온 로그 레벨 표를 일단 한 번 살펴보자.

Level Shortcut Description
PEAR_LOG_EMERG emerg() System is unusable
PEAR_LOG_ALERT alert() Immediate action required
PEAR_LOG_CRIT crit() Critical conditions
PEAR_LOG_ERR err() Error conditions
PEAR_LOG_WARNING warning() Warning conditions
PEAR_LOG_NOTICE notice() Normal but significant
PEAR_LOG_INFO info() Informational
PEAR_LOG_DEBUG debug() Debug-level messages

Level 값은 PEAR Log 패키지가 미리 정의한 값으로 log() 메소드 두번째 매개변수에 들어간다. 첨언하자면 PEAR_LOG_DEBUG가 가장 낮고, PEAR_LOG_EMERG가 가장 높은 레벨이다. 매번 log() 메소드에 로그 레벨 상수를 넣는 것이 번거롭다면 숏컷(Shortcut)을 사용 할 수도 있다.

1
2
$logger->log('Hello', PEAR_LOG_DEBUG);
$logger->debug('Hello'); // 위 문장과 동일하게 동작한다.

로그 레벨을 구별해서 기록하고 싶다면, Log 인스턴스를 생성 할 때 어느 로그 레벨 이상만 기록할지 지정 할 수 있다.

1
$logger = Log::singleton('file', 'levels.log', 'factorial', null, PEAR_LOG_ERR);

5번째 매개변수에 로그 레벨 상수를 넣으면 해당 로그 레벨 이상인 메시지만 해당 로그 리소스에 기록한다.

이미 생성한 Log 인스턴스를 특정 로그 레벨들만 기록하게 하고 싶다면 setMask() 메소드를 통해 로그 레벨을 지정하면 된다.

1
2
$mask = Log::MASK(PEAR_LOG_WARNING) | Log::MASK(PEAR_LOG_INFO);
$logger->setMask($mask); // Warning, Information 만 기록한다.

특정 로그 레벨 이상 또는 이하만 기록하고 싶다면 MAX(), MIN() 메소드를 이용한다.

1
2
$mask = Log::MAX(PEAR_LOG_CRIT); // Critical 이상만 기록한다.
$mask = Log::MIN(PEAR_LOG_NOTICE); // Notice 이하만 기록한다.

특정 로그 레벨을 제외한 나머지 로그 레벨들을 기록하려고 한다면 ^ 연산자를 이용해 마스크(Mask)를 지정한다.

1
$mask = PEAR_LOG_ALL ^ Log::MASK(PEAR_LOG_WARNING); // Warning 뺀 나머지 로그 레벨들을 기록한다.

Log 인스턴스에 특정 로그 레벨을 추가적으로 기록하고 싶다면 getMask() 메소드와 | 연산자를 이용해 마스크를 지정한다.

1
2
// 기록 중인 로그 레벨과 더불어 Warning 도 기록하게 한다.
$mask = $logger->getMask() | Log::MASK(PEAR_LOG_WARNING);

로그 라인 포맷

Log 인스턴스를 생성 할 때 설정값을 통해서 로그 라인의 형식을 기본 외의 형식으로 지정 할 수 있다. 형식에 사용하는 토큰은 다음과 같다.

Token Alternate Description
%{timestamp} %1$s Timestamp. This is often configurable.
%{ident} %2$s The log handler’s identification string.
%{priority} %3$s The log event’s priority.
%{message} %4$s The log event’s message text.
%{file} %5$s The full filename of the logging file.
%{line} %6$s The line number on which the event occured.
%{function} %7$s The function from which the event occurred.
%{class} %8$s The class in which the event occurred.

토큰을 이용해 정의한 로그 라인 형식은 Log 인스턴스 생성시 설정값 매개변수에 lineFormat 첨자로 전달한다.

1
2
3
4
5
$conf = array(
    'lineFormat' => '%{timestamp} %{ident} %{priority} %{message} %{file} %{line} %{function} %{class}',
);

$logger = Log::singleton('file', 'foobar.log', 'foobar', $conf);

로그 핸들러

Log 패키지에서 제공하는 다수의 로그 핸들러가 있다. 그 중 이전 글에서 다룬 consolefile 제외하고 몇개를 추려 간략한 사용법을 살펴보자.

Firebug

firebug 로그 핸들러는 파이어폭스(Firefox) Firebug 애드온의 콘솔 패널을 통해 로그 메시지를 출력하는 핸들러다.

1
$logger = Log::singleton('firebug', '', 'foobar');

SQL

sql 로그 핸들러는 데이터베이스에 로그 메시지를 기록한다. 데이터베이스 접근은 Log 패키지 안에서 PEAR DB를 이용한다. sql 핸들러를 사용하기 위해서는 로그를 저장 할 테이블을 미리 만들어야 한다. 기본값으로 사용하는 테이블 스키마는 다음과 같다.

1
2
3
4
5
6
7
8
CREATE TABLE log_table (
    id          INT NOT NULL,
    logtime     TIMESTAMP NOT NULL,
    ident       CHAR(16) NOT NULL,
    priority    INT NOT NULL,
    message     VARCHAR(200),
    PRIMARY KEY (id)
);

dsn은 사용하는 DBMS와 계정, 데이터베이스에 따라 설정한다. 자세한 형식은 DSN 문서에 나와있다.

1
2
$conf = array('dsn' => 'mysql://bookworm@localhost/test');
$logger = Log::singleton('sql', 'log_table', 'foobar', $conf);

Syslog

syslog 핸들러는 syslog 데몬을 통해서 로그 메시지를 기록한다. 정상적으로 기록하기 위해서는 syslog 데몬 설정을 미리 해두어야 한다.

1
$logger = Log::singleton('syslog', LOG_LOCAL0, 'foobar');

Window

win 핸들러는 웹브라우저에 새 창을 만든 후 그 안에 로그 메시지를 출력한다.

1
2
$conf = array('title' => 'Log Window');
$logger = Log::singleton('win', 'LogWindow', 'foobar', $conf);

Composite

composite 핸들러는 독립적으로 동작하지 않고, 다른 로그 핸들러를 통해서 메시지를 출력하도록 해준다. 이를 통해 여러 로그 리소스에 같은 메시지를 기록 할 수 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php

require 'Log.php';

$console = Log::singleton('console', '', 'foobar');
$file = Log::singleton('file', 'foobar.log', 'foobar');

$logger = Log::singleton('composite');
$logger->addChild($console); // console 로그 리소스를 composite 핸들러에 추가한다.
$logger->addChild($file); // file 로그 리소스를 composite 핸들러에 추가한다.
$logger->log('Hello'); // console과 file 로그 둘 다 출력한다.

$logger->removeChild($console);
$logger->log('Goodbye'); // console을 제거했기 때문에 file 로그에만 출력한다.

컴포져로 설치하기

컴포져(Composer)로 PEAR 패키지를 설치하는 일반적인 방법은 컴포져 설명서에 나와있으므로, 여기서는 Log 패키지에 한정해서 이야기를 해보려고 한다.

패키지스트(Packagist)에 이미 pear/log가 있으므로 require로 손쉽게 설치 할 수 있었다. 하지만, 언젠가부터 의존성 문제로 설치가 되지 않는다. 이 문제를 해결하기 위해서는 composer.jsondev-master 패키지를 설치하도록 설정해야 한다.

1
2
3
4
5
6
{
  "require": {
    "pear/log": "dev-master",
    "pear/pear_exception": "1.0.*@dev"
  }
}

PEAR Log 의존성 문제를 없애기 위해 PEAR_Exception 패키지로 함께 설치하도록 설정했다.

지금까지 PEAR의 Log 패키지에 대해 간략하게 다뤄보았다. 자세한 설정이나 기능에 대해서는 Log 패키지 문서를 통해 살펴 볼 수 있다.