Coverage Report

Created: 2025-07-01 06:08

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