1/* 2 * logger.c : Implementation of the SvnServe logger API 3 * 4 * ==================================================================== 5 * Licensed to the Apache Software Foundation (ASF) under one 6 * or more contributor license agreements. See the NOTICE file 7 * distributed with this work for additional information 8 * regarding copyright ownership. The ASF licenses this file 9 * to you under the Apache License, Version 2.0 (the 10 * "License"); you may not use this file except in compliance 11 * with the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, 16 * software distributed under the License is distributed on an 17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 * KIND, either express or implied. See the License for the 19 * specific language governing permissions and limitations 20 * under the License. 21 * ==================================================================== 22 */ 23 24 25 26#define APR_WANT_STRFUNC 27#include <apr_want.h> 28 29#include "svn_error.h" 30#include "svn_io.h" 31#include "svn_pools.h" 32#include "svn_time.h" 33 34#include "private/svn_mutex.h" 35 36#include "svn_private_config.h" 37#include "logger.h" 38 39#ifdef HAVE_UNISTD_H 40#include <unistd.h> /* For getpid() */ 41#endif 42 43struct logger_t 44{ 45 /* actual log file / stream object */ 46 svn_stream_t *stream; 47 48 /* mutex used to serialize access to this structure */ 49 svn_mutex__t *mutex; 50 51 /* private pool used for temporary allocations */ 52 apr_pool_t *pool; 53}; 54 55svn_error_t * 56logger__create_for_stderr(logger_t **logger, 57 apr_pool_t *pool) 58{ 59 logger_t *result = apr_pcalloc(pool, sizeof(*result)); 60 result->pool = svn_pool_create(pool); 61 62 SVN_ERR(svn_stream_for_stderr(&result->stream, pool)); 63 SVN_ERR(svn_mutex__init(&result->mutex, TRUE, pool)); 64 65 *logger = result; 66 67 return SVN_NO_ERROR; 68} 69 70svn_error_t * 71logger__create(logger_t **logger, 72 const char *filename, 73 apr_pool_t *pool) 74{ 75 logger_t *result = apr_pcalloc(pool, sizeof(*result)); 76 apr_file_t *file; 77 78 SVN_ERR(svn_io_file_open(&file, filename, 79 APR_WRITE | APR_CREATE | APR_APPEND, 80 APR_OS_DEFAULT, pool)); 81 SVN_ERR(svn_mutex__init(&result->mutex, TRUE, pool)); 82 83 result->stream = svn_stream_from_aprfile2(file, FALSE, pool); 84 result->pool = svn_pool_create(pool); 85 86 *logger = result; 87 88 return SVN_NO_ERROR; 89} 90 91static void 92log_message(logger_t *logger, 93 const svn_error_t *err, 94 const char *prefix, 95 repository_t *repository, 96 client_info_t *client_info) 97{ 98 if (logger && err) 99 { 100 const char *timestr, *continuation; 101 const char *user, *repos, *remote_host; 102 103 /* 8192 from MAX_STRING_LEN in from httpd-2.2.4/include/httpd.h */ 104 const apr_size_t errstr_size = 8192; 105 char *errstr = apr_palloc(logger->pool, errstr_size); 106 107 svn_error_clear(svn_mutex__lock(logger->mutex)); 108 109 timestr = svn_time_to_cstring(apr_time_now(), logger->pool); 110 remote_host = client_info && client_info->remote_host 111 ? client_info->remote_host 112 : "-"; 113 user = client_info && client_info->user 114 ? client_info->user 115 : "-"; 116 repos = repository && repository->repos_name 117 ? repository->repos_name 118 : "-"; 119 120 continuation = ""; 121 while (err) 122 { 123 char errbuf[256]; 124 const char *message = svn_err_best_message(err, errbuf, sizeof(errbuf)); 125 /* based on httpd-2.2.4/server/log.c:log_error_core */ 126 apr_size_t len = apr_snprintf(errstr, errstr_size, 127 "%" APR_PID_T_FMT 128 " %s %s %s %s %s%s %s %ld %d ", 129 getpid(), timestr, remote_host, user, 130 repos, prefix, continuation, 131 err->file ? err->file : "-", err->line, 132 err->apr_err); 133 134 len += escape_errorlog_item(errstr + len, message, 135 errstr_size - len); 136 /* Truncate for the terminator (as apr_snprintf does) */ 137 if (len > errstr_size - sizeof(APR_EOL_STR)) { 138 len = errstr_size - sizeof(APR_EOL_STR); 139 } 140 141 memcpy(errstr + len, APR_EOL_STR, sizeof(APR_EOL_STR)); 142 len += sizeof(APR_EOL_STR) -1; /* add NL, ex terminating NUL */ 143 144 svn_error_clear(svn_stream_write(logger->stream, errstr, &len)); 145 146 continuation = "-"; 147 err = err->child; 148 } 149 150 svn_pool_clear(logger->pool); 151 152 svn_error_clear(svn_mutex__unlock(logger->mutex, SVN_NO_ERROR)); 153 } 154} 155 156void 157logger__log_error(logger_t *logger, 158 const svn_error_t *err, 159 repository_t *repository, 160 client_info_t *client_info) 161{ 162 log_message(logger, err, "ERR", repository, client_info); 163} 164 165void 166logger__log_warning(logger_t *logger, 167 const svn_error_t *err, 168 repository_t *repository, 169 client_info_t *client_info) 170{ 171 log_message(logger, err, "WARN", repository, client_info); 172} 173 174svn_error_t * 175logger__write(logger_t *logger, 176 const char *errstr, 177 apr_size_t len) 178{ 179 SVN_MUTEX__WITH_LOCK(logger->mutex, 180 svn_stream_write(logger->stream, errstr, &len)); 181 return SVN_NO_ERROR; 182} 183