Coverage Report

Created: 2026-03-12 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/logging-log4cxx/src/main/cpp/writerappender.cpp
Line
Count
Source
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
51.0k
#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
352
  : AppenderSkeleton (std::move(priv))
62
352
{
63
64
352
}
log4cxx::WriterAppender::WriterAppender(std::__1::unique_ptr<log4cxx::WriterAppender::WriterAppenderPriv, std::__1::default_delete<log4cxx::WriterAppender::WriterAppenderPriv> >)
Line
Count
Source
61
352
  : AppenderSkeleton (std::move(priv))
62
352
{
63
64
352
}
Unexecuted instantiation: log4cxx::WriterAppender::WriterAppender(std::__1::unique_ptr<log4cxx::WriterAppender::WriterAppenderPriv, std::__1::default_delete<log4cxx::WriterAppender::WriterAppenderPriv> >)
65
66
WriterAppender::~WriterAppender()
67
352
{
68
352
  if (_priv->setClosed())
69
0
    _priv->close();
70
352
}
71
72
void WriterAppender::activateOptions(Pool& p)
73
704
{
74
704
  int errors = 0;
75
76
704
  if (_priv->layout == 0)
77
0
  {
78
0
    _priv->errorHandler->error(
79
0
      ((LogString) LOG4CXX_STR("No layout set for the appender named ["))
80
0
      + _priv->name + LOG4CXX_STR("]."));
81
0
    errors++;
82
0
  }
83
84
704
  if (_priv->writer == 0)
85
0
  {
86
0
    _priv->errorHandler->error(
87
0
      ((LogString) LOG4CXX_STR("No writer set for the appender named ["))
88
0
      + _priv->name + LOG4CXX_STR("]."));
89
0
    errors++;
90
0
  }
91
92
704
  if (errors == 0)
93
704
  {
94
704
    AppenderSkeleton::activateOptions(p);
95
704
  }
96
704
}
97
98
99
100
void WriterAppender::append(const spi::LoggingEventPtr& event, Pool& pool1)
101
3.52k
{
102
103
3.52k
  if (!checkEntryConditions())
104
0
  {
105
0
    return;
106
0
  }
107
108
3.52k
  subAppend(event, pool1);
109
3.52k
}
110
111
/**
112
   This method determines if there is a sense in attempting to append.
113
114
   <p>It checks whether there is a set output target and also if
115
   there is a set layout. If these checks fail, then the boolean
116
   value <code>false</code> is returned. */
117
bool WriterAppender::checkEntryConditions() const
118
3.52k
{
119
3.52k
  return _priv->checkWriter() && _priv->checkLayout() && _priv->checkNotClosed();
120
3.52k
}
121
122
bool WriterAppender::WriterAppenderPriv::checkWriter()
123
3.52k
{
124
3.52k
  if (this->writer == 0)
125
0
  {
126
0
    if (!this->warnedNoWriter)
127
0
    {
128
0
      this->errorHandler->error(
129
0
        LogString(LOG4CXX_STR("No output stream or file set for the appender named [")) +
130
0
        this->name + LOG4CXX_STR("]."));
131
0
      this->warnedNoWriter = true;
132
0
    }
133
0
    return false;
134
0
  }
135
3.52k
  return true;
136
3.52k
}
137
138
void WriterAppender::close()
139
352
{
140
352
  if (_priv->setClosed())
141
352
    _priv->close();
142
352
}
143
144
#if LOG4CXX_ABI_VERSION <= 15
145
/**
146
 * Close the underlying {@link java.io.Writer}.
147
 * */
148
void WriterAppender::closeWriter()
149
0
{
150
0
   _priv->close();
151
0
}
152
#endif
153
154
void WriterAppender::WriterAppenderPriv::close()
155
1.05k
{
156
1.05k
  if (this->writer != NULL)
157
705
  {
158
705
    try
159
705
    {
160
      // before closing we have to output out layout's footer
161
      //
162
      //   Using the object's pool since this is a one-shot operation
163
      //    and pool is likely to be reclaimed soon when appender is destructed.
164
      //
165
705
      this->writeFooter();
166
705
      this->writer->close(this->pool);
167
705
      this->writer = 0;
168
705
    }
169
705
    catch (IOException& e)
170
705
    {
171
0
      LogLog::warn(LOG4CXX_STR("Could not close writer for WriterAppender named ") + this->name, e);
172
0
    }
173
705
  }
174
175
1.05k
}
176
177
/**
178
   Returns an OutputStreamWriter when passed an OutputStream.  The
179
   encoding used will depend on the value of the
180
   <code>encoding</code> property.  If the encoding value is
181
   specified incorrectly the writer will be opened using the default
182
   system encoding (an error message will be printed to the loglog.  */
183
WriterPtr WriterAppender::createWriter(LOG4CXX_16_CONST OutputStreamPtr& os)
184
705
{
185
186
705
  LogString enc(getEncoding());
187
188
705
  CharsetEncoderPtr encoder;
189
190
705
  if (enc.empty())
191
705
  {
192
705
    encoder = CharsetEncoder::getDefaultEncoder();
193
705
  }
194
0
  else
195
0
  {
196
0
    if (StringHelper::equalsIgnoreCase(enc,
197
0
        LOG4CXX_STR("utf-16"), LOG4CXX_STR("UTF-16")))
198
0
    {
199
0
      encoder = CharsetEncoder::getEncoder(LOG4CXX_STR("UTF-16BE"));
200
0
    }
201
0
    else
202
0
    {
203
0
      encoder = CharsetEncoder::getEncoder(enc);
204
0
    }
205
206
0
    if (encoder == NULL)
207
0
    {
208
0
      encoder = CharsetEncoder::getDefaultEncoder();
209
0
      LogLog::warn(LOG4CXX_STR("Error initializing output writer."));
210
0
      LogLog::warn(LOG4CXX_STR("Unsupported encoding?"));
211
0
    }
212
0
  }
213
214
705
  return std::make_shared<OutputStreamWriter>(os, encoder);
215
705
}
216
217
LogString WriterAppender::getEncoding() const
218
1.41k
{
219
1.41k
  return _priv->encoding;
220
1.41k
}
221
222
void WriterAppender::setEncoding(const LogString& enc)
223
0
{
224
0
  _priv->encoding = enc;
225
0
}
226
227
void WriterAppender::subAppend(const spi::LoggingEventPtr& event, Pool& p)
228
3.52k
{
229
3.52k
  LogString msg;
230
3.52k
  _priv->layout->format(msg, event, p);
231
232
3.52k
  if (_priv->writer != NULL)
233
3.52k
  {
234
3.52k
    _priv->writer->write(msg, p);
235
236
3.52k
    if (_priv->immediateFlush)
237
3.52k
    {
238
3.52k
      _priv->writer->flush(p);
239
3.52k
    }
240
3.52k
  }
241
3.52k
}
242
243
244
#if LOG4CXX_ABI_VERSION <= 15
245
void WriterAppender::writeHeader(Pool& p)
246
0
{
247
0
  _priv->writeHeader();
248
0
}
249
250
void WriterAppender::writeFooter(Pool& p)
251
0
{
252
0
  _priv->writeFooter();
253
0
}
254
#endif
255
256
void WriterAppender::WriterAppenderPriv::writeFooter()
257
705
{
258
705
  if (this->layout != NULL)
259
705
  {
260
705
    Pool p;
261
705
    LogString foot;
262
705
    this->layout->appendFooter(foot, p);
263
705
    this->writer->write(foot, p);
264
705
  }
265
705
}
266
267
void WriterAppender::WriterAppenderPriv::writeHeader()
268
705
{
269
705
  if (this->layout != NULL)
270
705
  {
271
705
    Pool p;
272
705
    LogString header;
273
705
    this->layout->appendHeader(header, p);
274
705
    this->writer->write(header, p);
275
705
  }
276
705
}
277
278
279
#if LOG4CXX_ABI_VERSION <= 15
280
void WriterAppender::setWriter(const WriterPtr& newWriter)
281
0
{
282
0
  _priv->setWriter(newWriter);
283
0
}
284
285
void WriterAppender::setWriterInternal(const WriterPtr& newWriter)
286
0
{
287
0
  _priv->writer = newWriter;
288
0
}
289
#endif
290
291
bool WriterAppender::requiresLayout() const
292
0
{
293
0
  return true;
294
0
}
295
296
void WriterAppender::setOption(const LogString& option, const LogString& value)
297
0
{
298
0
  if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("ENCODING"), LOG4CXX_STR("encoding")))
299
0
  {
300
0
    setEncoding(value);
301
0
  }
302
0
  else
303
0
  {
304
0
    AppenderSkeleton::setOption(option, value);
305
0
  }
306
0
}
307
308
309
void WriterAppender::setImmediateFlush(bool value)
310
0
{
311
0
  _priv->immediateFlush = value;
312
0
}
313
314
bool WriterAppender::getImmediateFlush() const
315
0
{
316
0
  return _priv->immediateFlush;
317
0
}
318
319
#if LOG4CXX_ABI_VERSION <= 15
320
0
const LOG4CXX_NS::helpers::WriterPtr WriterAppender::getWriter() const{
321
0
  return _priv->writer;
322
0
}
323
#endif