blob: c484f8b436aebc1ab467dfcf6eeddca04401903b [file] [log] [blame]
/* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
* ====================================================================
*/
#include "serf.h"
#include "serf_private.h"
/* For optimizations, we allow logging to be disabled entirely. */
#ifdef SERF_LOGGING_ENABLED
typedef struct log_baton_t {
apr_array_header_t *output_list;
} log_baton_t;
typedef apr_status_t (*log_to_output_t)(serf_log_output_t *output,
serf_config_t *config,
apr_uint32_t level,
apr_uint32_t comp,
int header,
const char *prefix,
const char *fmt,
va_list argp);
struct serf_log_output_t {
apr_uint32_t level;
apr_uint32_t comps;
serf_log_layout_t *layout;
log_to_output_t logger;
void *baton;
};
const char * loglvl_labels[] = {
"",
"ERROR", /* 0x0001 */
"WARN ", /* 0x0002 */
"",
"INFO ", /* 0x0004 */
"",
"",
"",
"DEBUG", /* 0x0008 */
};
apr_status_t serf__log_init(serf_context_t *ctx)
{
log_baton_t *log_baton;
log_baton = apr_palloc(ctx->pool, sizeof(log_baton_t));
log_baton->output_list = apr_array_make(ctx->pool, 1,
sizeof(serf_log_output_t *));
return APR_SUCCESS;
}
static void log_time(FILE *logfp)
{
apr_time_exp_t tm;
apr_time_exp_lt(&tm, apr_time_now());
fprintf(logfp, "%d-%02d-%02dT%02d:%02d:%02d.%06d%+03d ",
1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec,
tm.tm_gmtoff/3600);
}
void serf__log_nopref(apr_uint32_t level, apr_uint32_t comp,
serf_config_t *config, const char *fmt, ...)
{
log_baton_t *log_baton;
apr_status_t status;
if (!config) {
/* If we can't get the log baton we have no choice but to silently
return without logging. */
return;
}
status = serf_config_get_object(config, SERF_CONFIG_CTX_LOGBATON,
(void **)&log_baton);
if (!status && log_baton) {
int i;
for (i = 0; i < log_baton->output_list->nelts; i++) {
serf_log_output_t *output = APR_ARRAY_IDX(log_baton->output_list,
i, serf_log_output_t *);
if ((output->level >= level) && (comp & output->comps)) {
va_list argp;
va_start(argp, fmt);
output->logger(output, config, level, comp, 0, "", fmt, argp);
va_end(argp);
}
}
}
}
void serf__log(apr_uint32_t level, apr_uint32_t comp, const char *prefix,
serf_config_t *config, const char *fmt, ...)
{
log_baton_t *log_baton;
apr_status_t status;
if (!config) {
/* If we can't get the log baton we have no choice but to silently
return without logging. */
return;
}
status = serf_config_get_object(config, SERF_CONFIG_CTX_LOGBATON,
(void **)&log_baton);
if (!status && log_baton) {
int i;
for (i = 0; i < log_baton->output_list->nelts; i++) {
serf_log_output_t *output = APR_ARRAY_IDX(log_baton->output_list,
i, serf_log_output_t *);
if ((output->level >= level) && (comp & output->comps)) {
va_list argp;
va_start(argp, fmt);
output->logger(output, config, level, comp, 1, prefix, fmt, argp);
va_end(argp);
}
}
}
}
int serf__log_enabled(apr_uint32_t level, apr_uint32_t comp, serf_config_t *config)
{
log_baton_t *log_baton;
apr_status_t status;
if (!config) {
/* If we can't get the log baton then logging is disabled for provided
level/component combination. */
return FALSE;
}
status = serf_config_get_object(config, SERF_CONFIG_CTX_LOGBATON,
(void **)&log_baton);
if (!status && log_baton) {
int i;
for (i = 0; i < log_baton->output_list->nelts; i++) {
serf_log_output_t *output = APR_ARRAY_IDX(log_baton->output_list,
i, serf_log_output_t *);
if ((output->level >= level) && (comp & output->comps)) {
/* At least one log output wants to handle this level/component
combination.*/
return TRUE;
}
}
}
return FALSE;
}
/*** Output to system stream (stderr or stdout) or a file ***/
static apr_status_t log_to_stream_output(serf_log_output_t *output,
serf_config_t *config,
apr_uint32_t level,
apr_uint32_t comp,
int header,
const char *prefix,
const char *fmt,
va_list argp)
{
if (output && output->baton) {
FILE *logfp = output->baton;
if (output->layout == SERF_LOG_DEFAULT_LAYOUT && header) {
const char *localip, *remoteip;
apr_status_t status;
log_time(logfp);
/* Log local and remote ip address:port */
fprintf(logfp, "%s [l:", loglvl_labels[level]);
status = serf_config_get_string(config, SERF_CONFIG_CONN_LOCALIP,
&localip);
if (!status && localip) {
fprintf(logfp, "%s", localip);
}
fprintf(logfp, " r:");
status = serf_config_get_string(config, SERF_CONFIG_CONN_REMOTEIP,
&remoteip);
if (!status && remoteip) {
fprintf(logfp, "%s", remoteip);
}
fprintf(logfp, "] ");
if (prefix)
fprintf(logfp, "%s: ", prefix);
}
vfprintf(logfp, fmt, argp);
return APR_SUCCESS;
}
return APR_EINVAL;
}
apr_status_t serf_logging_create_stream_output(serf_log_output_t **output,
serf_context_t *ctx,
apr_uint32_t level,
apr_uint32_t comp_mask,
serf_log_layout_t *layout,
FILE *fp,
apr_pool_t *pool)
{
serf_log_output_t *baton;
baton = apr_palloc(pool, sizeof(serf_log_output_t));
baton->baton = fp;
baton->logger = log_to_stream_output;
baton->level = level;
baton->comps = comp_mask;
baton->layout = layout;
*output = baton;
return APR_SUCCESS;
}
apr_status_t serf_logging_add_output(serf_context_t *ctx,
const serf_log_output_t *output)
{
apr_status_t status;
log_baton_t *log_baton;
status = serf_config_get_object(ctx->config, SERF_CONFIG_CTX_LOGBATON,
(void **)&log_baton);
if (!status && log_baton) {
APR_ARRAY_PUSH(log_baton->output_list, const serf_log_output_t *) = output;
}
return status;
}
#else
/* We wish to compile out all logging stubs. */
apr_status_t serf__log_init(serf_context_t *ctx)
{
return APR_SUCCESS;
}
void serf__log_nopref(apr_uint32_t level, apr_uint32_t comp,
serf_config_t *config, const char *fmt, ...)
{
}
void serf__log(apr_uint32_t level, apr_uint32_t comp, const char *prefix,
serf_config_t *config, const char *fmt, ...)
{
}
apr_status_t serf_logging_create_stream_output(serf_log_output_t **output,
serf_context_t *ctx,
apr_uint32_t level,
apr_uint32_t comp_mask,
serf_log_layout_t *layout,
FILE *fp,
apr_pool_t *pool)
{
return APR_SUCCESS;
}
apr_status_t serf_logging_add_output(serf_context_t *ctx,
const serf_log_output_t *output)
{
return APR_SUCCESS;
}
int serf__log_enabled(apr_uint32_t level, apr_uint32_t comp, serf_config_t *config)
{
return FALSE;
}
#endif