/* * logger.c : Implementation of the SvnServe logger API * * ==================================================================== * 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. * ==================================================================== */ #define APR_WANT_STRFUNC #include #include "svn_error.h" #include "svn_io.h" #include "svn_pools.h" #include "svn_time.h" #include "private/svn_mutex.h" #include "svn_private_config.h" #include "logger.h" #ifdef HAVE_UNISTD_H #include /* For getpid() */ #endif struct logger_t { /* actual log file / stream object */ svn_stream_t *stream; /* mutex used to serialize access to this structure */ svn_mutex__t *mutex; /* private pool used for temporary allocations */ apr_pool_t *pool; }; svn_error_t * logger__create_for_stderr(logger_t **logger, apr_pool_t *pool) { logger_t *result = apr_pcalloc(pool, sizeof(*result)); result->pool = svn_pool_create(pool); SVN_ERR(svn_stream_for_stderr(&result->stream, pool)); SVN_ERR(svn_mutex__init(&result->mutex, TRUE, pool)); *logger = result; return SVN_NO_ERROR; } svn_error_t * logger__create(logger_t **logger, const char *filename, apr_pool_t *pool) { logger_t *result = apr_pcalloc(pool, sizeof(*result)); apr_file_t *file; SVN_ERR(svn_io_file_open(&file, filename, APR_WRITE | APR_CREATE | APR_APPEND, APR_OS_DEFAULT, pool)); SVN_ERR(svn_mutex__init(&result->mutex, TRUE, pool)); result->stream = svn_stream_from_aprfile2(file, FALSE, pool); result->pool = svn_pool_create(pool); *logger = result; return SVN_NO_ERROR; } static void log_message(logger_t *logger, const svn_error_t *err, const char *prefix, repository_t *repository, client_info_t *client_info) { if (logger && err) { const char *timestr, *continuation; const char *user, *repos, *remote_host; /* 8192 from MAX_STRING_LEN in from httpd-2.2.4/include/httpd.h */ const apr_size_t errstr_size = 8192; char *errstr = apr_palloc(logger->pool, errstr_size); svn_error_clear(svn_mutex__lock(logger->mutex)); timestr = svn_time_to_cstring(apr_time_now(), logger->pool); remote_host = client_info && client_info->remote_host ? client_info->remote_host : "-"; user = client_info && client_info->user ? client_info->user : "-"; repos = repository && repository->repos_name ? repository->repos_name : "-"; continuation = ""; while (err) { char errbuf[256]; const char *message = svn_err_best_message(err, errbuf, sizeof(errbuf)); /* based on httpd-2.2.4/server/log.c:log_error_core */ apr_size_t len = apr_snprintf(errstr, errstr_size, "%" APR_PID_T_FMT " %s %s %s %s %s%s %s %ld %d ", getpid(), timestr, remote_host, user, repos, prefix, continuation, err->file ? err->file : "-", err->line, err->apr_err); len += escape_errorlog_item(errstr + len, message, errstr_size - len); /* Truncate for the terminator (as apr_snprintf does) */ if (len > errstr_size - sizeof(APR_EOL_STR)) { len = errstr_size - sizeof(APR_EOL_STR); } memcpy(errstr + len, APR_EOL_STR, sizeof(APR_EOL_STR)); len += sizeof(APR_EOL_STR) -1; /* add NL, ex terminating NUL */ svn_error_clear(svn_stream_write(logger->stream, errstr, &len)); continuation = "-"; err = err->child; } svn_pool_clear(logger->pool); svn_error_clear(svn_mutex__unlock(logger->mutex, SVN_NO_ERROR)); } } void logger__log_error(logger_t *logger, const svn_error_t *err, repository_t *repository, client_info_t *client_info) { log_message(logger, err, "ERR", repository, client_info); } void logger__log_warning(logger_t *logger, const svn_error_t *err, repository_t *repository, client_info_t *client_info) { log_message(logger, err, "WARN", repository, client_info); } svn_error_t * logger__write(logger_t *logger, const char *errstr, apr_size_t len) { SVN_MUTEX__WITH_LOCK(logger->mutex, svn_stream_write(logger->stream, errstr, &len)); return SVN_NO_ERROR; }