1289177Speter/*
2289177Speter * logger.c : Implementation of the SvnServe logger API
3289177Speter *
4289177Speter * ====================================================================
5289177Speter *    Licensed to the Apache Software Foundation (ASF) under one
6289177Speter *    or more contributor license agreements.  See the NOTICE file
7289177Speter *    distributed with this work for additional information
8289177Speter *    regarding copyright ownership.  The ASF licenses this file
9289177Speter *    to you under the Apache License, Version 2.0 (the
10289177Speter *    "License"); you may not use this file except in compliance
11289177Speter *    with the License.  You may obtain a copy of the License at
12289177Speter *
13289177Speter *      http://www.apache.org/licenses/LICENSE-2.0
14289177Speter *
15289177Speter *    Unless required by applicable law or agreed to in writing,
16289177Speter *    software distributed under the License is distributed on an
17289177Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18289177Speter *    KIND, either express or implied.  See the License for the
19289177Speter *    specific language governing permissions and limitations
20289177Speter *    under the License.
21289177Speter * ====================================================================
22289177Speter */
23289177Speter
24289177Speter
25289177Speter
26289177Speter#define APR_WANT_STRFUNC
27289177Speter#include <apr_want.h>
28289177Speter
29289177Speter#include "svn_error.h"
30289177Speter#include "svn_io.h"
31289177Speter#include "svn_pools.h"
32289177Speter#include "svn_time.h"
33289177Speter
34289177Speter#include "private/svn_mutex.h"
35289177Speter
36289177Speter#include "svn_private_config.h"
37289177Speter#include "logger.h"
38289177Speter
39289177Speter#ifdef HAVE_UNISTD_H
40289177Speter#include <unistd.h>   /* For getpid() */
41289177Speter#endif
42289177Speter
43289177Speterstruct logger_t
44289177Speter{
45289177Speter  /* actual log file / stream object */
46289177Speter  svn_stream_t *stream;
47289177Speter
48289177Speter  /* mutex used to serialize access to this structure */
49289177Speter  svn_mutex__t *mutex;
50289177Speter
51289177Speter  /* private pool used for temporary allocations */
52289177Speter  apr_pool_t *pool;
53289177Speter};
54289177Speter
55289177Spetersvn_error_t *
56289177Speterlogger__create_for_stderr(logger_t **logger,
57289177Speter                          apr_pool_t *pool)
58289177Speter{
59289177Speter  logger_t *result = apr_pcalloc(pool, sizeof(*result));
60289177Speter  result->pool = svn_pool_create(pool);
61289177Speter
62289177Speter  SVN_ERR(svn_stream_for_stderr(&result->stream, pool));
63289177Speter  SVN_ERR(svn_mutex__init(&result->mutex, TRUE, pool));
64289177Speter
65289177Speter  *logger = result;
66289177Speter
67289177Speter  return SVN_NO_ERROR;
68289177Speter}
69289177Speter
70289177Spetersvn_error_t *
71289177Speterlogger__create(logger_t **logger,
72289177Speter               const char *filename,
73289177Speter               apr_pool_t *pool)
74289177Speter{
75289177Speter  logger_t *result = apr_pcalloc(pool, sizeof(*result));
76289177Speter  apr_file_t *file;
77289177Speter
78289177Speter  SVN_ERR(svn_io_file_open(&file, filename,
79289177Speter                           APR_WRITE | APR_CREATE | APR_APPEND,
80289177Speter                           APR_OS_DEFAULT, pool));
81289177Speter  SVN_ERR(svn_mutex__init(&result->mutex, TRUE, pool));
82289177Speter
83289177Speter  result->stream = svn_stream_from_aprfile2(file, FALSE,  pool);
84289177Speter  result->pool = svn_pool_create(pool);
85289177Speter
86289177Speter  *logger = result;
87289177Speter
88289177Speter  return SVN_NO_ERROR;
89289177Speter}
90289177Speter
91289177Spetervoid
92289177Speterlogger__log_error(logger_t *logger,
93289177Speter                  svn_error_t *err,
94289177Speter                  repository_t *repository,
95289177Speter                  client_info_t *client_info)
96289177Speter{
97289177Speter  if (logger && err)
98289177Speter    {
99289177Speter      const char *timestr, *continuation;
100289177Speter      const char *user, *repos, *remote_host;
101289177Speter      char errbuf[256];
102289177Speter      /* 8192 from MAX_STRING_LEN in from httpd-2.2.4/include/httpd.h */
103289177Speter      char errstr[8192];
104289177Speter
105289177Speter      svn_error_clear(svn_mutex__lock(logger->mutex));
106289177Speter
107289177Speter      timestr = svn_time_to_cstring(apr_time_now(), logger->pool);
108289177Speter      remote_host = client_info && client_info->remote_host
109289177Speter                  ? client_info->remote_host
110289177Speter                  : "-";
111289177Speter      user = client_info && client_info->user
112289177Speter           ? client_info->user
113289177Speter           : "-";
114289177Speter      repos = repository && repository->repos_name
115289177Speter            ? repository->repos_name
116289177Speter             : "-";
117289177Speter
118289177Speter      continuation = "";
119289177Speter      while (err)
120289177Speter        {
121289177Speter          const char *message = svn_err_best_message(err, errbuf, sizeof(errbuf));
122289177Speter          /* based on httpd-2.2.4/server/log.c:log_error_core */
123289177Speter          apr_size_t len = apr_snprintf(errstr, sizeof(errstr),
124289177Speter                                        "%" APR_PID_T_FMT
125289177Speter                                        " %s %s %s %s ERR%s %s %ld %d ",
126289177Speter                                        getpid(), timestr, remote_host, user,
127289177Speter                                        repos, continuation,
128289177Speter                                        err->file ? err->file : "-", err->line,
129289177Speter                                        err->apr_err);
130289177Speter
131289177Speter          len += escape_errorlog_item(errstr + len, message,
132289177Speter                                      sizeof(errstr) - len);
133289177Speter          /* Truncate for the terminator (as apr_snprintf does) */
134289177Speter          if (len > sizeof(errstr) - sizeof(APR_EOL_STR)) {
135289177Speter            len = sizeof(errstr) - sizeof(APR_EOL_STR);
136289177Speter          }
137289177Speter
138289177Speter          memcpy(errstr + len, APR_EOL_STR, sizeof(APR_EOL_STR));
139289177Speter          len += sizeof(APR_EOL_STR) -1;  /* add NL, ex terminating NUL */
140289177Speter
141289177Speter          svn_error_clear(svn_stream_write(logger->stream, errstr, &len));
142289177Speter
143289177Speter          continuation = "-";
144289177Speter          err = err->child;
145289177Speter        }
146289177Speter
147289177Speter      svn_pool_clear(logger->pool);
148289177Speter
149289177Speter      svn_error_clear(svn_mutex__unlock(logger->mutex, SVN_NO_ERROR));
150289177Speter    }
151289177Speter}
152289177Speter
153289177Spetersvn_error_t *
154289177Speterlogger__write(logger_t *logger,
155289177Speter              const char *errstr,
156289177Speter              apr_size_t len)
157289177Speter{
158289177Speter  SVN_MUTEX__WITH_LOCK(logger->mutex,
159289177Speter                       svn_stream_write(logger->stream, errstr, &len));
160289177Speter  return SVN_NO_ERROR;
161289177Speter}
162