blob: 5ce77fdf7e7742922fad391a6e1b24c62020d296 [file] [log] [blame]
/*
* Copyright 1999-2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/***************************************************************************
* Description: Utility functions (mainly configuration) *
* Author: Gal Shachor <shachor@il.ibm.com> *
* Author: Henri Gomez <hgomez@apache.org> *
* Version: $Revision$ *
***************************************************************************/
#include "jk_env.h"
#include "jk_map.h"
#include "jk_logger.h"
#include <stdio.h>
#include <fcntl.h>
#include "jk_registry.h"
#define LOG_FORMAT ("log_format")
#define HUGE_BUFFER_SIZE (8*1024)
#define LOG_LINE_SIZE (1024)
/*
* define the log format, we're using by default the one from error.log
*
* [Mon Mar 26 19:44:48 2001] [jk_uri_worker_map.c (155)]: Into jk_uri_worker_map_t::uri_worker_map_alloc
* log format used by apache in error.log
*/
#ifndef JK_TIME_FORMAT
#define JK_TIME_FORMAT "[%a %b %d %H:%M:%S %Y] "
#endif
static const char *jk2_logger_file_logFmt = JK_TIME_FORMAT;
static void jk2_logger_file_setTimeStr(jk_env_t *env, char *str, int len)
{
apr_time_exp_t gmt;
apr_size_t l;
apr_time_exp_gmt(&gmt, apr_time_now());
apr_strftime(str, &l, len, jk2_logger_file_logFmt, &gmt);
}
static int JK_METHOD jk2_logger_file_log(jk_env_t *env, jk_logger_t *l,
int level, const char *what)
{
apr_status_t rv = APR_SUCCESS;
apr_file_t *f = (apr_file_t *) l->logger_private;
if (f == NULL) {
/* This is usefull to debug what happens before logger is set.
On apache you need -X option ( no detach, single process ) */
if (what != NULL)
fprintf(stderr, what);
return JK_OK;
}
if (l && l->level <= level && l->logger_private && what) {
rv = apr_file_puts(what, f);
/* flush the log for each entry only for debug level */
if (rv == APR_SUCCESS && l->level == JK_LOG_DEBUG_LEVEL)
rv = apr_file_flush(f);
return JK_OK;
}
return JK_ERR;
}
int jk2_logger_file_parseLogLevel(jk_env_t *env, const char *level)
{
if (!level)
return JK_LOG_INFO_LEVEL;
if (!strcasecmp(level, JK_LOG_INFO_VERB))
return JK_LOG_INFO_LEVEL;
if (!strcasecmp(level, JK_LOG_ERROR_VERB))
return JK_LOG_ERROR_LEVEL;
if (!strcasecmp(level, JK_LOG_EMERG_VERB))
return JK_LOG_EMERG_LEVEL;
return JK_LOG_DEBUG_LEVEL;
}
static int JK_METHOD jk2_logger_file_init(jk_env_t *env, jk_logger_t *_this)
{
apr_status_t rv;
apr_file_t *oldF = (apr_file_t *) _this->logger_private;
int closeOld;
apr_file_t *f = NULL;
jk_workerEnv_t *workerEnv = env->getByName(env, "workerEnv");
/* workaround for APR insanity - APR closes the global system
stderr handle and invalidates all references to stderr if you
call apr_file_close on any stderr reference. Just don't close
stderr references. */
closeOld = oldF != NULL && _this->name != NULL &&
strcmp("stderr", _this->name) != 0;
if (!_this->name) {
_this->name = "${serverRoot}/logs/jk2.log";
}
_this->name = jk2_config_replaceProperties(env, workerEnv->initData,
_this->mbean->pool,
_this->name);
if (!_this->name || !strcmp("stderr", _this->name)) {
if ((rv = apr_file_open_stderr(&f, env->globalPool->_private)) !=
APR_SUCCESS) {
_this->jkLog(env, _this, JK_LOG_ERROR,
"Can't open stderr file\n");
return JK_ERR;
}
_this->logger_private = f;
}
else {
if ((rv = apr_file_open(&f, _this->name,
APR_APPEND | APR_READ | APR_WRITE |
APR_CREATE, APR_OS_DEFAULT,
env->globalPool->_private)) != APR_SUCCESS) {
_this->jkLog(env, _this, JK_LOG_ERROR, "Can't open log file %s\n",
_this->name);
return JK_ERR;
}
_this->logger_private = f;
}
_this->jkLog(env, _this, JK_LOG_INFO,
"Initializing log file %s\n", _this->name);
if (closeOld) {
apr_file_close(oldF);
}
return JK_OK;
}
static int jk2_logger_file_close(jk_env_t *env, jk_logger_t *_this)
{
apr_status_t rv;
apr_file_t *f = _this->logger_private;
if (!f)
return JK_OK;
apr_file_flush(f);
rv = apr_file_close(f);
_this->logger_private = NULL;
/* free(_this); */
return JK_OK;
}
static int JK_METHOD
jk2_logger_file_setProperty(jk_env_t *env, jk_bean_t *mbean,
char *name, void *valueP)
{
jk_logger_t *_this = mbean->object;
char *value = valueP;
if (!strcmp(name, "name"))
_this->name = (char *)value;
else if (!strcmp(name, "file")) {
_this->name = (char *)value;
/* Set the file imediately */
jk2_logger_file_init(env, (jk_logger_t *)mbean->object);
}
else if (!strcmp(name, "timeFormat"))
jk2_logger_file_logFmt = value;
else if (!strcmp(name, "level")) {
_this->level = jk2_logger_file_parseLogLevel(env, value);
if (_this->level == 0) {
_this->jkLog(env, _this, JK_LOG_INFO,
"Level %s %d \n", value, _this->level);
}
}
return JK_OK;
}
static int JK_METHOD jk2_logger_file_jkVLog(jk_env_t *env, jk_logger_t *l,
const char *file,
int line,
int level,
const char *fmt, va_list args)
{
int rc = 0;
char *buf;
char *fmt1;
apr_pool_t *aprPool = env->tmpPool->_private;
char rfctime[APR_RFC822_DATE_LEN];
apr_time_t time = apr_time_now();
if (!file || !args)
return -1;
if (l->logger_private == NULL || l->level <= level) {
char *f = (char *)(file + strlen(file) - 1);
char *slevel;
switch (level) {
case JK_LOG_INFO_LEVEL:
slevel = JK_LOG_INFO_VERB;
break;
case JK_LOG_ERROR_LEVEL:
slevel = JK_LOG_ERROR_VERB;
break;
case JK_LOG_EMERG_LEVEL:
slevel = JK_LOG_EMERG_VERB;
break;
case JK_LOG_DEBUG_LEVEL:
default:
slevel = JK_LOG_DEBUG_VERB;
break;
}
while (f != file && *f != '\\' && *f != '/')
f--;
if (f != file)
++f;
/* XXX rfc822_date or apr_ctime ? */
apr_ctime(rfctime, time);
fmt1 =
apr_psprintf(aprPool, "[%s] (%5s ) [%s (%d)] %s", rfctime,
slevel, f, line, fmt);
buf = apr_pvsprintf(aprPool, fmt1, args);
l->log(env, l, level, buf);
}
return rc;
}
static int jk2_logger_file_jkLog(jk_env_t *env, jk_logger_t *l,
const char *file,
int line, int level, const char *fmt, ...)
{
va_list args;
int rc;
va_start(args, fmt);
rc = jk2_logger_file_jkVLog(env, l, file, line, level, fmt, args);
va_end(args);
return rc;
}
int JK_METHOD jk2_logger_file_factory(jk_env_t *env, jk_pool_t *pool,
jk_bean_t *result,
const char *type, const char *name)
{
jk_logger_t *log =
(jk_logger_t *)pool->calloc(env, pool, sizeof(jk_logger_t));
if (log == NULL) {
fprintf(stderr, "loggerFile.factory(): OutOfMemoryException\n");
return JK_ERR;
}
log->log = jk2_logger_file_log;
log->logger_private = NULL;
log->init = jk2_logger_file_init;
log->jkLog = jk2_logger_file_jkLog;
log->jkVLog = jk2_logger_file_jkVLog;
log->level = JK_LOG_ERROR_LEVEL;
jk2_logger_file_logFmt = JK_TIME_FORMAT;
result->object = log;
log->mbean = result;
result->setAttribute = jk2_logger_file_setProperty;
return JK_OK;
}