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