ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [CodeIgniter] 로그 파일 분리하기 (로그 확장)
    프로그래밍/CodeIgniter 2019. 1. 19. 23:58

    ▶CodeIgniter 로그 파일 분리하기 (로그 확장)



    ▶설명


    이전 글에서 코드이그나이터(CodeIgniter)에서 로그를 기록하는 법에 관해 작성했습니다.


    이번에는 로그 파일을 확장하여 좀 더 편리하게 사용하는 방법을 알려드리도록 하겠습니다.

    ※ 설명하는 확장 방법은 코드이그나이터 3 기준입니다.


    기본적인 뼈대는 아래의 출처입니다. (코드이그나이터 2 기준 설명)


    코어 확장에 대해 자세히 알고 싶으시면 아래의 링크를 확인하시기 바랍니다.


    ▶목표


    이 글에서 목표는 총 3가지입니다.


    1. 로그 종류에 모니터링(Monitoring) 로그 추가

    info 로그를 사용하면 클래스 초기화 같은 불필요한 로그가 많이 남기 때문에,

    이를 대신해 원하는 정보만 기록하기 위한 로그로 모니터링(Monitoring) 로그를 추가하겠습니다.


    2. 로그 종류에 따른 파일 분리

    코드이그나이터에 로그 파일의 이름은 기본적으로 'log-년-월-일.php'로 기록됩니다.

    그렇지만, 좀 더 알아보기 쉽게 로그 종류에 따라 로그 파일명이 다르도록 수정할 것입니다.

    • error : error-년-월-일.php
    • debug : debug-년-월-일.php
    • info : info-년-월-일.php
    • mon : mon-년-월-일.php

    ※ mon은 새로 추가하는 모니터링(Monitoring) 로그입니다.


    3. 로그 헬퍼(Helper) 추가

    조금 더 간단하게 로그를 기록할 수 있도록 헬퍼를 추가하도록 하겠습니다.


    ▶나만의 클래스 접두어 확인 (또는 설정)


    로그 확장을 위해 일단 코드이그나이터에 설정된 나만의 클래스 접두어 설정을 확인합니다.


    application/config/config.php

    $config['subclass_prefix'] = 'MY_';


    접두어가 'MY_' 이기 때문에 확장을 위해 생성하는 로그 파일 이름은 'MY_Log'입니다.


    ※ 다른 이름으로 사용하고 싶으시다면 접두어를 변경하시기 바랍니다.


    ※ 'CI_' 는 코드이그나이터 기본 접두어이므로 사용해서는 안됩니다!!!


    ▶로그 쓰레스홀드 (log Threshold) 수정



    application/config/config.php

    /*
    |--------------------------------------------------------------------------
    | Error Logging Threshold
    |--------------------------------------------------------------------------
    |
    | You can enable error logging by setting a threshold over zero. The
    | threshold determines what gets logged. Threshold options are:
    |
    |	0 = Disables logging, Error logging TURNED OFF
    |	1 = Error Messages (including PHP errors)
    |	2 = Debug Messages
    |	3 = Informational Messages
    |	4 = Monitoring Messages
    |	5 = All Messages
    |
    | You can also pass an array with threshold levels to show individual error types
    |
    | 	array(2) = Debug Messages, without Error Messages
    |
    | For a live site you'll usually only enable Errors (1) to be logged otherwise
    | your log files will fill up very fast.
    |
    */
    $config['log_threshold'] = array(1, 4);
    

    error와 monitoring만을 출력할 것이기 때문에 로그 쓰레스홀드를 수정하도록 하겠습니다.

    또한, monitoring 로그를 추가할 것이기 때문에 주석도 수정하도록 하겠습니다.


    추가된 Monitoring은 4번으로 추가하도록 하겠습니다.

    주석에서 기존에 4번이었던 ALL은 Monitoring이 추가되었기 때문에 5번으로 변경합니다.


    ※ ALL은 로그 레벨 가운데 가장 높은 숫자여야 합니다. (그래야만 ALL 값으로 설정했을 때, 전체 로그가 남습니다.)


    ▶로그 확장


    로그 확장을 위해 core 폴더에 확장 로그 파일을 생성하겠습니다.


    application/core/MY_Log.php

    <?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
    
    class MY_Log extends CI_Log {
        
        protected $_enabled = TRUE;
        protected $_date_fmt    = 'Y-m-d H:i:s';
        protected $_levels = array(
            'ERROR' => 1,
            'DEBUG' => 2,
            'INFO'  => 3,
            'MON'   => 4,
            'ALL'   => 5,
        );
        
        public function __construct()
        {
            parent::__construct();
        }
        
        public function write_log($level, $msg)
        {
            if ($this->_enabled === FALSE)
            {
                return FALSE;
            }
            
            $level = strtoupper($level);
            
            if (( ! isset($this->_levels[$level]) OR ($this->_levels[$level] > $this->_threshold))
            && ! isset($this->_threshold_array[$this->_levels[$level]]))
            {
                return FALSE;
            }
            
            // $filepath = $this->_log_path.'log-'.date('Y-m-d').'.'.$this->_file_ext;
            $filepath = $this->_log_path.strtolower($level).'-'.date('Y-m-d').'.'.$this->_file_ext;
            $message = '';
            
            if ( ! file_exists($filepath))
            {
                $newfile = TRUE;
                // Only add protection to php files
                if ($this->_file_ext === 'php')
                {
                    $message .= "<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>\n\n";
                }
            }
            
            if ( ! $fp = @fopen($filepath, 'ab'))
            {
                return FALSE;
            }
            
            flock($fp, LOCK_EX);
            
            // Instantiating DateTime with microseconds appended to initial date is needed for proper support of this format
            if (strpos($this->_date_fmt, 'u') !== FALSE)
            {
                $microtime_full = microtime(TRUE);
                $microtime_short = sprintf("%06d", ($microtime_full - floor($microtime_full)) * 1000000);
                $date = new DateTime(date('Y-m-d H:i:s.'.$microtime_short, $microtime_full));
                $date = $date->format($this->_date_fmt);
            }
            else
            {
                $date = date($this->_date_fmt);
            }
            
            // $message .= $this->_format_line($level, $date, $msg);
            $message .= $this->_format_line_simple($date, $msg);
            
            for ($written = 0, $length = self::strlen($message); $written < $length; $written += $result)
            {
                if (($result = fwrite($fp, self::substr($message, $written))) === FALSE)
                {
                    break;
                }
            }
            
            flock($fp, LOCK_UN);
            fclose($fp);
            
            if (isset($newfile) && $newfile === TRUE)
            {
                chmod($filepath, $this->_file_permissions);
            }
            
            return is_int($result);
        }
        
        protected function _format_line_simple($date, $message)
        {
            return $date.' --> '.$message."\n";
        }
    }
    // END MY_Log Class
    
    /* End of file MY_Log.php */
    /* Location: ./application/core/MY_Log.php */


    기존 로그를 기반으로 CI_Log를 상속 받는 MY_Log를 생성하였습니다.

    기존에 system/core/Log.php에서 수정된 사항만 간단하게 정리하도록 하겠습니다.


    모니터링(Monitoring) 로그 추가

    protected $_levels = array(
        'ERROR' => 1,
        'DEBUG' => 2,
        'INFO'  => 3,
        'MON'   => 4,
        'ALL'   => 5,
    );


    위에서 설명했지만, Monitorng 로그를 4번으로 추가했습니다.


    로그 종류에 따라 파일 분리

    // $filepath = $this->_log_path.'log-'.date('Y-m-d').'.'.$this->_file_ext;
    $filepath = $this->_log_path.strtolower($level).'-'.date('Y-m-d').'.'.$this->_file_ext;

    로그 종류에 따라 파일명이 다르도록 변경했습니다.


    또한

    // $message .= $this->_format_line($level, $date, $msg);
    $message .= $this->_format_line_simple($date, $msg);
    protected function _format_line_simple($date, $message)
    {
        return $date.' --> '.$message."\n";
    }

    이제 로그 종류가 파일명에 표시되기 때문에, 로그 종류를 로그 내용에서 제거했습니다.


    ▶로그 확장 테스트


    로그 확장 테스트를 위한 컨트롤러를 생성하겠습니다.

    전에 만들었던 로그 컨트롤러를 사용하겠습니다.

    없으시다면 새로 만드시면 됩니다.


    application/controllers/Log.php

    <?php
    defined('BASEPATH') OR exit('No direct script access allowed');
     
    class Log extends CI_Controller {
     
        public function __construct()
        {
            parent::__construct();
        }
     
        public function index()
        {
            log_message("error", "Error Message");
            log_message("debug", "Debug Message");
            log_message("info", "Informational Message");
            log_message("mon", "Monitoring Message");
        }
    }

    물론 monitoring 로그에 대한 코드가 추가되었습니다.


    index 실행 결과

    application/logs 폴더에 아래와 같이 나오면 성공입니다.

    (물론 파일의 날짜는 다를 수 있습니다.)


    error-2019-01-19.php

    <?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>
    
    2019-01-19 14:56:34 --> Error Message


    mon-2019-01-19.php

    <?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>
    
    2019-01-19 14:56:34 --> Monitoring Message


    ▶로그 헬퍼 추가


    이제 로그를 좀 더 쉽게 남기기 위해 로그 헬퍼를 추가하도록 하겠습니다.


    application/helpers/log_helper.php

    <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
    
    if(!function_exists('log_error')) {
    
        function log_error($msg, $obj=null, $debug_backtrace=true)
        {
            if($obj != null)
            {
                $msg = $msg . ' : ' . print_r($obj, true);
            }
    
            if($debug_backtrace == true)
            {
                $d = debug_backtrace();
                if($d != null && is_array($d) && count($d) > 1)
                {
                    $debug = $d[1];
                    $msg = sprintf("[%s::%s] %s", $debug['class'], $debug['function'], $msg);
                }
            }
    
            log_message('error', $msg);
        }
    }
    
    if(!function_exists('log_mon')) {
    
        function log_mon($msg, $obj=null, $debug_backtrace=true)
        {
            if($obj != null)
            {
                $msg = $msg . ' : ' . print_r($obj, true);
            }
    
            if($debug_backtrace == true)
            {
                $d = debug_backtrace();
                if($d != null && is_array($d) && count($d) > 1)
                {
                    $debug = $d[1];
                    $msg = sprintf("[%s::%s] %s", $debug['class'], $debug['function'], $msg);
                }
            }
            
            log_message('mon', $msg);
        }
    }

    로그 헬퍼에는 단 두개의 함수만 추가했습니다.

    1. log_error : 에러 로그 기록
    2. log_mon :  모니터링 로그 기록


    2개의 함수의 파라미터는 동일합니다.

    1. 메세지 : 로그에 기록할 메세지입니다.
    2. 데이터 : 로그에 기록할 변수 값입니다. (array, object)
    3. 역추적 여부 : 로그 기록을 호출한 클래스와 함수를 기록 여부입니다.


    ※ 역추적 여부는 debug_backtrace()가 속도 저하를 시킬 수 있기 때문에, 사용하지 않으시려면 기본값을 false로 처리하시거나, 제거하셔도 됩니다.


    ▶로그 헬퍼 자동 로드


    이제 로그 헬퍼를 자동으로 로드하도록 autoload에 추가하도록 하겠습니다.


    application/config/autoload.php

    $autoload['helper'] = array('log');

    이제 원하는 부분에서 로그 헬퍼에 있는 함수를 호출하면 됩니다.


    ▶로그 헬퍼 테스트


    위에 만들어 놓은 컨트롤러에서 pretty라는 메소드를 하나 추가하도록 하겠습니다.

    그리고 데이터를 어떻게 기록하는지 확인하기 위해 데이터도 전달하도록 하겠습니다.


    이전 테스트로 생성된 로그 파일은 일단 삭제해주시기 바랍니다.


    application/controllers/Log.php

    <?php
    defined('BASEPATH') OR exit('No direct script access allowed');
     
    class Log extends CI_Controller {
     
        public function __construct()
        {
            parent::__construct();
        }
     
        public function index()
        {
            log_message("error", "Error Message");
            log_message("debug", "Debug Message");
            log_message("info", "Informational Message");
            log_message("mon", "Monitoring Message");
        }
    
        public function pretty()
        {
            $data = array(
                'name' => 'Edward',
                'age' => '17'
            );
    
            log_error("Error Message!!!", $data);
            log_mon("Monitoring Message!!!", $data);
        }
    }


    pretty 실행 결과

    application/logs 폴더에 아래와 같이 나오면 성공입니다.

    (물론 파일의 날짜는 다를 수 있습니다.)


    error-2019-01-19.php

    <?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>
    
    2019-01-19 15:12:09 --> [Log::pretty] Error Message!!! : Array
    (
        [name] => Edward
        [age] => 17
    )


    mon-2019-01-19.php

    <?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>
    
    2019-01-19 15:12:09 --> [Log::pretty] Monitoring Message!!! : Array
    (
        [name] => Edward
        [age] => 17
    )


    로그를 기록한 클래스와 함수가 남는 것을 확인할 수 있습니다.


    ▶마치며


    코드이그나이터에서 로그를 확장하여, 편리하게 사용하는 방법을 알아봤습니다.

    위에 내용을 참고하여 자신의 입맛에 맞게 변경하여 사용하도록 합시다.



    댓글

Designed by Tistory.