/*  -
   Copyright (C) 2006 Weongyo Jeong (weongyo@gmail.com)

This file is part of ROVM.

ROVM is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.

ROVM is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING.  If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.  */

#include "types.h"
#include "mpool.h"
#include "tktree.h"
#include "clstree.h"
#include "sha1.h"
#include "listen.h"
#include "rovm.h"

#include "thread.h"
#include "thread_mutex.h"
#include "thread_cond.h"

#include "mpm_worker_fdqueue.h"
#include "mpm_worker_pod.h"
#include "mpm_worker.h"

#include "connection.h"
#include "request.h"

#include "log.h"
#include "utils.h"
#include "request.h"
#include "proc_rc.h"

/**
   로그의 level 을 담기 위한 구조체.
 */
typedef struct 
{
  /** 이름.  */
  char	*t_name;
  /** level.  */
  int	t_val;
} TRANS;

/**
   로그 level 구조체 변수.
 */
static const TRANS priorities[] = 
  {
    {"emerg",	ROVMLOG_EMERG},
    {"alert",	ROVMLOG_ALERT},
    {"crit",	ROVMLOG_CRIT},
    {"error",	ROVMLOG_ERR},
    {"warn",	ROVMLOG_WARNING},
    {"notice",	ROVMLOG_NOTICE},
    {"info",	ROVMLOG_INFO},
    {"debug",	ROVMLOG_DEBUG},
    {NULL,	-1},
  };

/**
   rovm_log () 함수에 의해 호출된다.  이 함수는 실제로 log 를 파일 혹은 stderr 에
   남기는 operation 을 수행한다.

   @param r	ROVM 구조체
   @param level 현재 로그의 위험도 등급
   @param file	메세지가 발생한 파일 이름
   @param line	메세지가 발생한 파일의 라인 번호
   @param fmt	vprintf 관련 포맷
   @param args	vprintf 관련 인자 포맷
 */
static void 
rovm_log_core (r, level, file, line, fmt, args)
     struct rovm *r;
     int level;
     const char *file;
     int line;
     const char *fmt;
     va_list args;
{
  char errstr[MAX_STRING_LEN];
  size_t len;
  int save_errno = errno;
  FILE *logf;
  
  if (r == NULL) 
    {
      /*
       * If we are doing stderr logging (startup), don't log messages that are
       * above the default server log level unless it is a startup/shutdown
       * notice
       */
      if (((level & ROVMLOG_LEVELMASK) != ROVMLOG_NOTICE) &&
	  ((level & ROVMLOG_LEVELMASK) > DEFAULT_LOGLEVEL))
	return;
      logf = stderr;
    }
  else if (r && !(CONF_OPTION (ROVM_CONF (r)) & OPTION_LOG_DEBUG_MESSAGES))
    /* 만약 Debug message 를 기록하지 않을 경우, 그냥 돌아간다.  */
    return;
  else if (CONF_ERROR_LOG (ROVM_CONF (r)))
    {
      /*
       * If we are doing normal logging, don't log messages that are
       * above the server log level unless it is a startup/shutdown notice
       */
      if (((level & ROVMLOG_LEVELMASK) != ROVMLOG_NOTICE) &&
	  ((level & ROVMLOG_LEVELMASK) > CONF_LOGLEVEL (ROVM_CONF (r))))
	return;
      logf = CONF_ERROR_LOG (ROVM_CONF (r));
    }
  else 
    {
      /*
       * If we are doing syslog logging, don't log messages that are
       * above the server log level (including a startup/shutdown notice)
       */
      if ((level & ROVMLOG_LEVELMASK) > CONF_LOGLEVEL (ROVM_CONF (r)))
	return;
      logf = NULL;
    }
  
  if (logf) 
    len = snprintf (errstr, sizeof (errstr), "[%s][0x%p]", get_current_timestr (), r);
  else 
    len = 0;

  len += snprintf (errstr + len, sizeof(errstr) - len,
		   "[%s] ", priorities[level & ROVMLOG_LEVELMASK].t_name);
  
  if (file && (level & ROVMLOG_LEVELMASK) == ROVMLOG_DEBUG) 
    {
      len += snprintf (errstr + len, sizeof(errstr) - len,
		       "%s(%d): ", file, line);
    }
  
  if ((level & ROVMLOG_WITHERRNO) && (save_errno != 0))
    {
      len += snprintf(errstr + len, sizeof(errstr) - len,
		      "(%d)%s: ", save_errno, strerror (save_errno));
    }
  
  len += vsnprintf (errstr + len, sizeof(errstr) - len, fmt, args);
  
  /* NULL if we are logging to syslog */
  if (logf) 
    {
      fputs(errstr, logf);
      fputc('\n', logf);
      fflush(logf);
    }
}

/**
   ROVM 에서 발생하는 모든 메세지를 기록하기 위해서 사용하는 logger 함수.

   @param r	ROVM 구조체
   @param level 현재 로그의 위험도 등급
   @param file	메세지가 발생한 파일 이름
   @param line	메세지가 발생한 파일의 라인 번호
   @param fmt	vprintf 관련 포맷
 */
void 
rovm_log (struct rovm *r,
	  int level,
	  const char *file, 
	  int line, 
	  const char *fmt, ...)
{
  va_list args;

  va_start (args, fmt);
  rovm_log_core (r, level, file, line, fmt, args);
  va_end (args);
}

/**
   ROVM Request 에서 발생하는 모든 메세지를 기록하기 위해서 사용하는 logger 함수.

   @param r	Request 구조체
   @param level 현재 로그의 위험도 등급
   @param file	메세지가 발생한 파일 이름
   @param line	메세지가 발생한 파일의 라인 번호
   @param fmt	vprintf 관련 포맷
 */
void 
rovm_rlog (request_rec *r,
	  int level,
	  const char *file, 
	  int line, 
	  const char *fmt, ...)
{
  va_list args;

  if (!r)
    return;

  va_start (args, fmt);
  rovm_log_core (r->conn->ts->arg, level, file, line, fmt, args);
  va_end (args);
}
