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 91void 92logger__log_error(logger_t *logger, 93 svn_error_t *err, 94 repository_t *repository, 95 client_info_t *client_info) 96{ 97 if (logger && err) 98 { 99 const char *timestr, *continuation; 100 const char *user, *repos, *remote_host; 101 char errbuf[256]; 102 /* 8192 from MAX_STRING_LEN in from httpd-2.2.4/include/httpd.h */ 103 char errstr[8192]; 104 105 svn_error_clear(svn_mutex__lock(logger->mutex)); 106 107 timestr = svn_time_to_cstring(apr_time_now(), logger->pool); 108 remote_host = client_info && client_info->remote_host 109 ? client_info->remote_host 110 : "-"; 111 user = client_info && client_info->user 112 ? client_info->user 113 : "-"; 114 repos = repository && repository->repos_name 115 ? repository->repos_name 116 : "-"; 117 118 continuation = ""; 119 while (err) 120 { 121 const char *message = svn_err_best_message(err, errbuf, sizeof(errbuf)); 122 /* based on httpd-2.2.4/server/log.c:log_error_core */ 123 apr_size_t len = apr_snprintf(errstr, sizeof(errstr), 124 "%" APR_PID_T_FMT 125 " %s %s %s %s ERR%s %s %ld %d ", 126 getpid(), timestr, remote_host, user, 127 repos, continuation, 128 err->file ? err->file : "-", err->line, 129 err->apr_err); 130 131 len += escape_errorlog_item(errstr + len, message, 132 sizeof(errstr) - len); 133 /* Truncate for the terminator (as apr_snprintf does) */ 134 if (len > sizeof(errstr) - sizeof(APR_EOL_STR)) { 135 len = sizeof(errstr) - sizeof(APR_EOL_STR); 136 } 137 138 memcpy(errstr + len, APR_EOL_STR, sizeof(APR_EOL_STR)); 139 len += sizeof(APR_EOL_STR) -1; /* add NL, ex terminating NUL */ 140 141 svn_error_clear(svn_stream_write(logger->stream, errstr, &len)); 142 143 continuation = "-"; 144 err = err->child; 145 } 146 147 svn_pool_clear(logger->pool); 148 149 svn_error_clear(svn_mutex__unlock(logger->mutex, SVN_NO_ERROR)); 150 } 151} 152 153svn_error_t * 154logger__write(logger_t *logger, 155 const char *errstr, 156 apr_size_t len) 157{ 158 SVN_MUTEX__WITH_LOCK(logger->mutex, 159 svn_stream_write(logger->stream, errstr, &len)); 160 return SVN_NO_ERROR; 161} 162