xref: /freebsd-13-stable/contrib/subversion/subversion/svnserve/logger.c (revision b7ec5dea64b6513b41316a38cc72efa9139bc4ae)
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