Coverage Report

Created: 2025-07-18 06:17

/src/logging-log4cxx/src/main/cpp/writerappender.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
#include <log4cxx/writerappender.h>
19
#include <log4cxx/helpers/loglog.h>
20
#include <log4cxx/layout.h>
21
#include <log4cxx/helpers/stringhelper.h>
22
#include <log4cxx/private/appenderskeleton_priv.h>
23
#include <log4cxx/private/writerappender_priv.h>
24
#include <mutex>
25
26
using namespace LOG4CXX_NS;
27
using namespace LOG4CXX_NS::helpers;
28
using namespace LOG4CXX_NS::spi;
29
30
0
#define _priv static_cast<WriterAppenderPriv*>(m_priv.get())
31
32
IMPLEMENT_LOG4CXX_OBJECT(WriterAppender)
33
34
WriterAppender::WriterAppender() :
35
0
  AppenderSkeleton (std::make_unique<WriterAppenderPriv>())
36
0
{
37
0
}
Unexecuted instantiation: log4cxx::WriterAppender::WriterAppender()
Unexecuted instantiation: log4cxx::WriterAppender::WriterAppender()
38
39
#if LOG4CXX_ABI_VERSION <= 15
40
WriterAppender::WriterAppender(const LayoutPtr& layout, helpers::WriterPtr& writer)
41
0
  : AppenderSkeleton (std::make_unique<WriterAppenderPriv>(layout, writer))
42
0
{
43
0
  Pool p;
44
0
  activateOptions(p);
45
0
}
Unexecuted instantiation: log4cxx::WriterAppender::WriterAppender(std::__1::shared_ptr<log4cxx::Layout> const&, std::__1::shared_ptr<log4cxx::helpers::Writer>&)
Unexecuted instantiation: log4cxx::WriterAppender::WriterAppender(std::__1::shared_ptr<log4cxx::Layout> const&, std::__1::shared_ptr<log4cxx::helpers::Writer>&)
46
47
WriterAppender::WriterAppender(const LayoutPtr& layout)
48
0
  : AppenderSkeleton (std::make_unique<WriterAppenderPriv>(layout))
49
0
{
50
0
}
Unexecuted instantiation: log4cxx::WriterAppender::WriterAppender(std::__1::shared_ptr<log4cxx::Layout> const&)
Unexecuted instantiation: log4cxx::WriterAppender::WriterAppender(std::__1::shared_ptr<log4cxx::Layout> const&)
51
#else
52
WriterAppender::WriterAppender(const LayoutPtr& layout, const helpers::WriterPtr& writer)
53
  : AppenderSkeleton(std::make_unique<WriterAppenderPriv>(layout, writer))
54
{
55
  Pool p;
56
  activateOptions(p);
57
}
58
#endif
59
60
WriterAppender::WriterAppender(std::unique_ptr<WriterAppenderPriv> priv)
61
0
  : AppenderSkeleton (std::move(priv))
62
0
{
63
64
0
}
Unexecuted instantiation: log4cxx::WriterAppender::WriterAppender(std::__1::unique_ptr<log4cxx::WriterAppender::WriterAppenderPriv, std::__1::default_delete<log4cxx::WriterAppender::WriterAppenderPriv> >)
Unexecuted instantiation: log4cxx::WriterAppender::WriterAppender(std::__1::unique_ptr<log4cxx::WriterAppender::WriterAppenderPriv, std::__1::default_delete<log4cxx::WriterAppender::WriterAppenderPriv> >)
65
66
WriterAppender::~WriterAppender()
67
0
{
68
0
  finalize();
69
0
}
70
71
void WriterAppender::activateOptions(Pool& p)
72
0
{
73
0
  int errors = 0;
74
75
0
  if (_priv->layout == 0)
76
0
  {
77
0
    _priv->errorHandler->error(
78
0
      ((LogString) LOG4CXX_STR("No layout set for the appender named ["))
79
0
      + _priv->name + LOG4CXX_STR("]."));
80
0
    errors++;
81
0
  }
82
83
0
  if (_priv->writer == 0)
84
0
  {
85
0
    _priv->errorHandler->error(
86
0
      ((LogString) LOG4CXX_STR("No writer set for the appender named ["))
87
0
      + _priv->name + LOG4CXX_STR("]."));
88
0
    errors++;
89
0
  }
90
91
0
  if (errors == 0)
92
0
  {
93
0
    AppenderSkeleton::activateOptions(p);
94
0
  }
95
0
}
96
97
98
99
void WriterAppender::append(const spi::LoggingEventPtr& event, Pool& pool1)
100
0
{
101
102
0
  if (!checkEntryConditions())
103
0
  {
104
0
    return;
105
0
  }
106
107
0
  subAppend(event, pool1);
108
0
}
109
110
/**
111
   This method determines if there is a sense in attempting to append.
112
113
   <p>It checks whether there is a set output target and also if
114
   there is a set layout. If these checks fail, then the boolean
115
   value <code>false</code> is returned. */
116
bool WriterAppender::checkEntryConditions() const
117
0
{
118
0
  return _priv->checkWriter() && _priv->checkLayout() && _priv->checkNotClosed();
119
0
}
120
121
bool WriterAppender::WriterAppenderPriv::checkWriter()
122
0
{
123
0
  if (this->writer == 0)
124
0
  {
125
0
    if (!this->warnedNoWriter)
126
0
    {
127
0
      this->errorHandler->error(
128
0
        LogString(LOG4CXX_STR("No output stream or file set for the appender named [")) +
129
0
        this->name + LOG4CXX_STR("]."));
130
0
      this->warnedNoWriter = true;
131
0
    }
132
0
    return false;
133
0
  }
134
0
  return true;
135
0
}
136
137
138
139
140
/**
141
   Close this appender instance. The underlying stream or writer is
142
   also closed.
143
144
   <p>Closed appenders cannot be reused.
145
146
   @see #setWriter
147
   */
148
void WriterAppender::close()
149
0
{
150
0
  std::lock_guard<std::recursive_mutex> lock(_priv->mutex);
151
152
0
  if (_priv->closed)
153
0
  {
154
0
    return;
155
0
  }
156
157
0
  _priv->closed = true;
158
0
  closeWriter();
159
0
}
160
161
/**
162
 * Close the underlying {@link java.io.Writer}.
163
 * */
164
void WriterAppender::closeWriter()
165
0
{
166
0
  if (_priv->writer != NULL)
167
0
  {
168
0
    try
169
0
    {
170
      // before closing we have to output out layout's footer
171
      //
172
      //   Using the object's pool since this is a one-shot operation
173
      //    and pool is likely to be reclaimed soon when appender is destructed.
174
      //
175
0
      writeFooter(_priv->pool);
176
0
      _priv->writer->close(_priv->pool);
177
0
      _priv->writer = 0;
178
0
    }
179
0
    catch (IOException& e)
180
0
    {
181
0
      LogLog::error(LogString(LOG4CXX_STR("Could not close writer for WriterAppender named ")) + _priv->name, e);
182
0
    }
183
0
  }
184
185
0
}
186
187
/**
188
   Returns an OutputStreamWriter when passed an OutputStream.  The
189
   encoding used will depend on the value of the
190
   <code>encoding</code> property.  If the encoding value is
191
   specified incorrectly the writer will be opened using the default
192
   system encoding (an error message will be printed to the loglog.  */
193
WriterPtr WriterAppender::createWriter(LOG4CXX_16_CONST OutputStreamPtr& os)
194
0
{
195
196
0
  LogString enc(getEncoding());
197
198
0
  CharsetEncoderPtr encoder;
199
200
0
  if (enc.empty())
201
0
  {
202
0
    encoder = CharsetEncoder::getDefaultEncoder();
203
0
  }
204
0
  else
205
0
  {
206
0
    if (StringHelper::equalsIgnoreCase(enc,
207
0
        LOG4CXX_STR("utf-16"), LOG4CXX_STR("UTF-16")))
208
0
    {
209
0
      encoder = CharsetEncoder::getEncoder(LOG4CXX_STR("UTF-16BE"));
210
0
    }
211
0
    else
212
0
    {
213
0
      encoder = CharsetEncoder::getEncoder(enc);
214
0
    }
215
216
0
    if (encoder == NULL)
217
0
    {
218
0
      encoder = CharsetEncoder::getDefaultEncoder();
219
0
      LogLog::warn(LOG4CXX_STR("Error initializing output writer."));
220
0
      LogLog::warn(LOG4CXX_STR("Unsupported encoding?"));
221
0
    }
222
0
  }
223
224
0
  return std::make_shared<OutputStreamWriter>(os, encoder);
225
0
}
226
227
LogString WriterAppender::getEncoding() const
228
0
{
229
0
  return _priv->encoding;
230
0
}
231
232
void WriterAppender::setEncoding(const LogString& enc)
233
0
{
234
0
  _priv->encoding = enc;
235
0
}
236
237
void WriterAppender::subAppend(const spi::LoggingEventPtr& event, Pool& p)
238
0
{
239
0
  LogString msg;
240
0
  _priv->layout->format(msg, event, p);
241
242
0
  if (_priv->writer != NULL)
243
0
  {
244
0
    _priv->writer->write(msg, p);
245
246
0
    if (_priv->immediateFlush)
247
0
    {
248
0
      _priv->writer->flush(p);
249
0
    }
250
0
  }
251
0
}
252
253
254
void WriterAppender::writeFooter(Pool& p)
255
0
{
256
0
  if (_priv->layout != NULL)
257
0
  {
258
0
    LogString foot;
259
0
    _priv->layout->appendFooter(foot, p);
260
0
    _priv->writer->write(foot, p);
261
0
  }
262
0
}
263
264
void WriterAppender::writeHeader(Pool& p)
265
0
{
266
0
  if (_priv->layout != NULL)
267
0
  {
268
0
    LogString header;
269
0
    _priv->layout->appendHeader(header, p);
270
0
    _priv->writer->write(header, p);
271
0
  }
272
0
}
273
274
275
void WriterAppender::setWriter(const WriterPtr& newWriter)
276
0
{
277
0
  std::lock_guard<std::recursive_mutex> lock(_priv->mutex);
278
0
  setWriterInternal(newWriter);
279
0
}
280
281
void WriterAppender::setWriterInternal(const WriterPtr& newWriter)
282
0
{
283
0
  _priv->writer = newWriter;
284
0
}
285
286
bool WriterAppender::requiresLayout() const
287
0
{
288
0
  return true;
289
0
}
290
291
void WriterAppender::setOption(const LogString& option, const LogString& value)
292
0
{
293
0
  if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("ENCODING"), LOG4CXX_STR("encoding")))
294
0
  {
295
0
    setEncoding(value);
296
0
  }
297
0
  else
298
0
  {
299
0
    AppenderSkeleton::setOption(option, value);
300
0
  }
301
0
}
302
303
304
void WriterAppender::setImmediateFlush(bool value)
305
0
{
306
0
  _priv->immediateFlush = value;
307
0
}
308
309
bool WriterAppender::getImmediateFlush() const
310
0
{
311
0
  return _priv->immediateFlush;
312
0
}
313
314
0
const LOG4CXX_NS::helpers::WriterPtr WriterAppender::getWriter() const{
315
0
  return _priv->writer;
316
0
}