Coverage Report

Created: 2026-08-31 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/logging-log4cxx/src/main/cpp/loggingevent.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 <chrono>
19
#include <mutex>
20
#include <log4cxx/spi/loggingevent.h>
21
#include <log4cxx/ndc.h>
22
23
#include <log4cxx/level.h>
24
#include <log4cxx/helpers/loglog.h>
25
#include <log4cxx/helpers/system.h>
26
#include <log4cxx/helpers/socket.h>
27
#if !defined(LOG4CXX)
28
  #define LOG4CXX 1
29
#endif
30
#include <log4cxx/helpers/aprinitializer.h>
31
#include <log4cxx/helpers/threadspecificdata.h>
32
#include <log4cxx/helpers/bytebuffer.h>
33
#include <log4cxx/helpers/messagebuffer.h>
34
#include <log4cxx/helpers/date.h>
35
#include <log4cxx/helpers/optional.h>
36
#include <log4cxx/helpers/transcoder.h>
37
#include <atomic>
38
#include <memory>
39
#include <thread>
40
41
using namespace LOG4CXX_NS;
42
using namespace LOG4CXX_NS::spi;
43
using namespace LOG4CXX_NS::helpers;
44
45
struct LoggingEvent::LoggingEventPrivate
46
{
47
  LoggingEventPrivate(const ThreadSpecificData::NamePairPtr p = ThreadSpecificData::getNames()) :
48
0
    timeStamp(0),
49
0
    pNames(p)
50
0
    , renderState(RenderingRequired)
51
0
  {
52
0
  }
53
54
  LoggingEventPrivate
55
    ( const LogString& logger1
56
    , const LevelPtr& level1
57
    , const LocationInfo& locationInfo1
58
    , LogString&& message1
59
    , const ThreadSpecificData::NamePairPtr p = ThreadSpecificData::getNames()
60
    ) :
61
0
    logger(logger1),
62
0
    level(level1),
63
0
    message(std::move(message1)),
64
0
    timeStamp(Date::currentTime()),
65
0
    locationInfo(locationInfo1),
66
0
    chronoTimeStamp(std::chrono::microseconds(timeStamp)),
67
0
    pNames(p),
68
0
    renderState(RenderingCompleted)
69
0
  {
70
0
  }
71
72
  LoggingEventPrivate
73
    ( const LogString& logger1
74
    , const LevelPtr& level1
75
    , const LocationInfo& locationInfo1
76
    , helpers::AsyncBuffer&& messageAppenderArg
77
    , const ThreadSpecificData::NamePairPtr p = ThreadSpecificData::getNames()
78
    )
79
0
    : logger(logger1)
80
0
    , level(level1)
81
0
    , timeStamp(Date::currentTime())
82
0
    , locationInfo(locationInfo1)
83
0
    , chronoTimeStamp(std::chrono::microseconds(timeStamp))
84
0
    , pNames(p)
85
0
    , messageAppender(std::move(messageAppenderArg))
86
0
    , renderState(RenderingRequired)
87
0
  {
88
0
  }
89
90
  LoggingEventPrivate(
91
    const LogString& logger1, const LevelPtr& level1,
92
    const LogString& message1, const LocationInfo& locationInfo1,
93
    const ThreadSpecificData::NamePairPtr& p = ThreadSpecificData::getNames()
94
    ) :
95
0
    logger(logger1),
96
0
    level(level1),
97
0
    message(message1),
98
0
    timeStamp(Date::currentTime()),
99
0
    locationInfo(locationInfo1),
100
0
    chronoTimeStamp(std::chrono::microseconds(timeStamp)),
101
0
    pNames(p),
102
0
    renderState(RenderingCompleted)
103
0
  {
104
0
  }
105
106
  ~LoggingEventPrivate()
107
0
  {
108
0
    delete properties;
109
0
  }
110
111
  /**
112
  * The name of the logger used to make the logging request
113
  **/
114
  LogString logger;
115
116
  /** severity level of logging event. */
117
  LevelPtr level;
118
119
  /**
120
  * A map of String keys and String values.
121
  */
122
  std::map<LogString, LogString>* properties{NULL};
123
124
  /** The application supplied message. */
125
  LogString message;
126
127
128
  /** The number of microseconds elapsed since 1970-01-01
129
   *  at the time this logging event was created.
130
   */
131
  log4cxx_time_t timeStamp;
132
133
  /** The source code location where the logging request was made. */
134
  const spi::LocationInfo locationInfo;
135
136
  std::chrono::time_point<std::chrono::system_clock> chronoTimeStamp;
137
138
  /**
139
   *  Thread names that remain valid for the lifetime of this LoggingEvent
140
   *  (i.e. even after thread termination).
141
   */
142
  ThreadSpecificData::NamePairPtr pNames;
143
144
  struct DiagnosticContext
145
  {
146
    Optional<NDC::DiagnosticContext> ctx;
147
    MDC::Map map;
148
  };
149
  /**
150
   *  Used to hold the diagnostic context when the lifetime
151
   *  of this LoggingEvent exceeds the duration of the logging request.
152
   */
153
  mutable std::unique_ptr<DiagnosticContext> dc;
154
155
  /** Application supplied message builders.
156
   */
157
  helpers::AsyncBuffer messageAppender;
158
159
  /** Ensures an async message is rendered exactly once.
160
   *
161
   *  A LoggingEvent may be shared between threads, e.g. when it is
162
   *  queued to an AsyncAppender dispatcher while the logging thread
163
   *  formats the same event for a synchronous appender.  Without this,
164
   *  two threads could pass the empty() check concurrently: one clears
165
   *  the closure vector while the other iterates it, and both
166
   *  move-assign \c message - a concurrent free/assign of the same
167
   *  heap buffer.
168
   * Note: use of std::call_once was found to degrade throughput by up to 120%
169
   */
170
  std::atomic<uint8_t> renderState;
171
  static const uint8_t RenderingRequired = 0;
172
  static const uint8_t RenderingActive = 1;
173
  static const uint8_t RenderingCompleted = 2;
174
175
  void renderMessage()
176
0
  {
177
0
    if (renderState.load(std::memory_order_acquire) == RenderingCompleted)
178
0
      return;
179
0
    uint8_t unrenderedState{ RenderingRequired };
180
0
    if (renderState.compare_exchange_strong(unrenderedState, RenderingActive, std::memory_order_acquire))
181
0
    {
182
0
      if (this->messageAppender.empty())
183
0
        ;
184
0
      else try
185
0
      {
186
0
        helpers::LogCharMessageBuffer buf;
187
0
        this->messageAppender.renderMessage(buf);
188
0
        this->message = buf.extract_str(buf);
189
0
        this->messageAppender.clear();
190
191
0
      }
192
0
      catch (const std::exception& e)
193
0
      {
194
0
        helpers::Transcoder::decode(e.what(), this->message);
195
0
      }
196
0
      catch (...)
197
0
      {
198
0
        this->message = LOG4CXX_STR("mesage rendering failed");
199
0
      }
200
0
      renderState.store(RenderingCompleted, std::memory_order_release);
201
0
    }
202
0
    else while (renderState.load(std::memory_order_acquire) != RenderingCompleted)
203
0
      std::this_thread::yield();
204
0
  }
205
};
206
207
IMPLEMENT_LOG4CXX_OBJECT(LoggingEvent)
208
209
210
//
211
//   Accessor for start time.
212
//
213
log4cxx_time_t LoggingEvent::getStartTime()
214
0
{
215
0
  return APRInitializer::getStartTime();
216
0
}
217
218
LoggingEvent::LoggingEvent() :
219
0
  m_priv(std::make_unique<LoggingEventPrivate>())
220
0
{
221
0
}
Unexecuted instantiation: log4cxx::spi::LoggingEvent::LoggingEvent()
Unexecuted instantiation: log4cxx::spi::LoggingEvent::LoggingEvent()
222
223
LoggingEvent::LoggingEvent
224
  ( const LogString&    logger
225
  , const LevelPtr&     level
226
  , const LocationInfo& location
227
  , LogString&&         message
228
  )
229
0
  : m_priv(std::make_unique<LoggingEventPrivate>(logger, level, location, std::move(message)))
230
0
{
231
0
}
Unexecuted instantiation: log4cxx::spi::LoggingEvent::LoggingEvent(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::shared_ptr<log4cxx::Level> const&, log4cxx::spi::LocationInfo const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&)
Unexecuted instantiation: log4cxx::spi::LoggingEvent::LoggingEvent(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::shared_ptr<log4cxx::Level> const&, log4cxx::spi::LocationInfo const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&)
232
233
LoggingEvent::LoggingEvent
234
  ( const LogString&    logger
235
  , const LevelPtr&     level
236
  , const LocationInfo& location
237
  , helpers::AsyncBuffer&& messageAppender
238
  )
239
0
  : m_priv(std::make_unique<LoggingEventPrivate>(logger, level, location, std::move(messageAppender)))
240
0
{
241
0
}
Unexecuted instantiation: log4cxx::spi::LoggingEvent::LoggingEvent(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::shared_ptr<log4cxx::Level> const&, log4cxx::spi::LocationInfo const&, log4cxx::helpers::AsyncBuffer&&)
Unexecuted instantiation: log4cxx::spi::LoggingEvent::LoggingEvent(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::shared_ptr<log4cxx::Level> const&, log4cxx::spi::LocationInfo const&, log4cxx::helpers::AsyncBuffer&&)
242
243
LoggingEvent::LoggingEvent(
244
  const LogString& logger1, const LevelPtr& level1,
245
  const LogString& message1, const LocationInfo& locationInfo1) :
246
0
  m_priv(std::make_unique<LoggingEventPrivate>(logger1, level1, message1, locationInfo1))
247
0
{
248
0
}
Unexecuted instantiation: log4cxx::spi::LoggingEvent::LoggingEvent(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::shared_ptr<log4cxx::Level> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, log4cxx::spi::LocationInfo const&)
Unexecuted instantiation: log4cxx::spi::LoggingEvent::LoggingEvent(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::shared_ptr<log4cxx::Level> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, log4cxx::spi::LocationInfo const&)
249
250
LoggingEvent::~LoggingEvent()
251
0
{
252
0
}
253
254
const LogString& LoggingEvent::getThreadUserName() const
255
0
{
256
0
  return m_priv->pNames->threadName;
257
0
}
258
259
bool LoggingEvent::getNDC(LogString& dest) const
260
0
{
261
0
  bool result = false;
262
  // Use the copy of the diagnostic context if it exists.
263
  // Otherwise use the NDC that is associated with the thread.
264
0
  if (m_priv->dc)
265
0
  {
266
0
    result = bool(m_priv->dc->ctx);
267
0
    if (result)
268
0
      dest.append(NDC::getFullMessage(m_priv->dc->ctx.value()));
269
0
  }
270
0
  else
271
0
    result = NDC::get(dest);
272
0
  return result;
273
0
}
274
275
bool LoggingEvent::getMDC(const LogString& key, LogString& dest) const
276
0
{
277
0
  bool result = false;
278
  // Use the copy of the diagnostic context if it exists.
279
  // Otherwise use the MDC that is associated with the thread.
280
0
  if (m_priv->dc)
281
0
  {
282
0
    auto& map = m_priv->dc->map;
283
0
    auto it = map.find(key);
284
0
    if (it != map.end() && !it->second.empty())
285
0
    {
286
0
      dest.append(it->second);
287
0
      result = true;
288
0
    }
289
0
  }
290
0
  else
291
0
    result = MDC::get(key, dest);
292
0
  return result;
293
0
}
294
295
LoggingEvent::KeySet LoggingEvent::getMDCKeySet() const
296
0
{
297
0
  LoggingEvent::KeySet result;
298
0
  if (m_priv->dc)
299
0
  {
300
0
    for (auto const& item : m_priv->dc->map)
301
0
      result.push_back(item.first);
302
0
  }
303
0
  else if (auto pData = ThreadSpecificData::getCurrentData())
304
0
  {
305
0
    for (auto const& item : pData->getMap())
306
0
      result.push_back(item.first);
307
0
  }
308
0
  return result;
309
0
}
310
311
void LoggingEvent::LoadDC() const
312
0
{
313
0
  m_priv->dc = std::make_unique<LoggingEventPrivate::DiagnosticContext>();
314
0
  if (auto pData = ThreadSpecificData::getCurrentData())
315
0
  {
316
0
    m_priv->dc->map = pData->getMap();
317
0
    auto& stack = pData->getStack();
318
0
    if (!stack.empty())
319
0
      m_priv->dc->ctx = stack.top();
320
0
  }
321
0
}
322
323
#if LOG4CXX_ABI_VERSION <= 15
324
void LoggingEvent::getMDCCopy() const
325
0
{
326
0
  if (!m_priv->dc)
327
0
    LoadDC();
328
0
}
329
#endif
330
331
bool LoggingEvent::getProperty(const LogString& key, LogString& dest) const
332
0
{
333
0
  if (m_priv->properties == 0)
334
0
  {
335
0
    return false;
336
0
  }
337
338
0
  std::map<LogString, LogString>::const_iterator  it = m_priv->properties->find(key);
339
340
0
  if (it != m_priv->properties->end())
341
0
  {
342
0
    dest.append(it->second);
343
0
    return true;
344
0
  }
345
346
0
  return false;
347
0
}
348
349
LoggingEvent::KeySet LoggingEvent::getPropertyKeySet() const
350
0
{
351
0
  LoggingEvent::KeySet set;
352
353
0
  if (m_priv->properties)
354
0
  {
355
0
    for (auto item : *m_priv->properties)
356
0
    {
357
0
      set.push_back(item.first);
358
0
    }
359
0
  }
360
361
0
  return set;
362
0
}
363
364
void LoggingEvent::renderMessage()
365
0
{
366
0
  m_priv->renderMessage();
367
0
}
368
369
void LoggingEvent::setProperty(const LogString& key, const LogString& value)
370
0
{
371
0
  if (m_priv->properties == 0)
372
0
  {
373
0
    m_priv->properties = new std::map<LogString, LogString>;
374
0
  }
375
376
0
  (*m_priv->properties)[key] = value;
377
0
}
378
379
const LevelPtr& LoggingEvent::getLevel() const
380
0
{
381
0
  return m_priv->level;
382
0
}
383
384
const LogString& LoggingEvent::getLoggerName() const
385
0
{
386
0
  return m_priv->logger;
387
0
}
388
389
const LogString& LoggingEvent::getMessage() const
390
0
{
391
0
  return m_priv->message;
392
0
}
393
394
const LogString& LoggingEvent::getRenderedMessage() const
395
0
{
396
0
  m_priv->renderMessage();
397
0
  return m_priv->message;
398
0
}
399
400
const LogString& LoggingEvent::getThreadName() const
401
0
{
402
0
  return m_priv->pNames->idString;
403
0
}
404
405
log4cxx_time_t LoggingEvent::getTimeStamp() const
406
0
{
407
0
  return m_priv->timeStamp;
408
0
}
409
410
const LOG4CXX_NS::spi::LocationInfo& LoggingEvent::getLocationInformation() const
411
0
{
412
0
  return m_priv->locationInfo;
413
0
}
414
415
0
std::chrono::time_point<std::chrono::system_clock> LoggingEvent::getChronoTimeStamp() const{
416
0
  return m_priv->chronoTimeStamp;
417
0
}
418