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
43 struct 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
55 svn_error_t *
logger__create_for_stderr(logger_t ** logger,apr_pool_t * pool)56 logger__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
70 svn_error_t *
logger__create(logger_t ** logger,const char * filename,apr_pool_t * pool)71 logger__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
91 static void
log_message(logger_t * logger,const svn_error_t * err,const char * prefix,repository_t * repository,client_info_t * client_info)92 log_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
156 void
logger__log_error(logger_t * logger,const svn_error_t * err,repository_t * repository,client_info_t * client_info)157 logger__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
165 void
logger__log_warning(logger_t * logger,const svn_error_t * err,repository_t * repository,client_info_t * client_info)166 logger__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
174 svn_error_t *
logger__write(logger_t * logger,const char * errstr,apr_size_t len)175 logger__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