Coverage Report

Created: 2026-05-30 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/logging-log4cxx/src/main/cpp/fixedwindowrollingpolicy.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
#include <log4cxx/logstring.h>
18
#include <log4cxx/rolling/fixedwindowrollingpolicy.h>
19
#include <log4cxx/helpers/pool.h>
20
#include <log4cxx/helpers/integer.h>
21
#include <log4cxx/helpers/stringhelper.h>
22
#include <log4cxx/helpers/optionconverter.h>
23
#include <log4cxx/helpers/loglog.h>
24
#include <log4cxx/helpers/exception.h>
25
#include <log4cxx/rolling/rolloverdescription.h>
26
#include <log4cxx/rolling/filerenameaction.h>
27
#include <log4cxx/rolling/gzcompressaction.h>
28
#include <log4cxx/rolling/zipcompressaction.h>
29
#include <log4cxx/pattern/integerpatternconverter.h>
30
#include <log4cxx/private/rollingpolicybase_priv.h>
31
32
using namespace LOG4CXX_NS;
33
using namespace LOG4CXX_NS::rolling;
34
using namespace LOG4CXX_NS::helpers;
35
using namespace LOG4CXX_NS::pattern;
36
37
0
#define priv static_cast<FixedWindowRollingPolicyPrivate*>(m_priv.get())
38
39
struct FixedWindowRollingPolicy::FixedWindowRollingPolicyPrivate : public RollingPolicyBasePrivate {
40
  FixedWindowRollingPolicyPrivate() :
41
0
    RollingPolicyBasePrivate(),
42
0
    minIndex(1),
43
0
    maxIndex(7),
44
0
    explicitActiveFile(false)
45
0
  {}
46
47
  int minIndex;
48
  int maxIndex;
49
  bool explicitActiveFile;
50
  bool throwIOExceptionOnForkFailure = true;
51
};
52
53
IMPLEMENT_LOG4CXX_OBJECT(FixedWindowRollingPolicy)
54
55
FixedWindowRollingPolicy::FixedWindowRollingPolicy() :
56
0
  RollingPolicyBase (std::make_unique<FixedWindowRollingPolicyPrivate>())
57
0
{
58
0
}
Unexecuted instantiation: log4cxx::rolling::FixedWindowRollingPolicy::FixedWindowRollingPolicy()
Unexecuted instantiation: log4cxx::rolling::FixedWindowRollingPolicy::FixedWindowRollingPolicy()
59
60
0
FixedWindowRollingPolicy::~FixedWindowRollingPolicy(){}
61
62
void FixedWindowRollingPolicy::setMaxIndex(int maxIndex1)
63
0
{
64
0
  priv->maxIndex = maxIndex1;
65
0
}
66
67
void FixedWindowRollingPolicy::setMinIndex(int minIndex1)
68
0
{
69
0
  priv->minIndex = minIndex1;
70
0
}
71
72
void FixedWindowRollingPolicy::setOption(const LogString& option,
73
  const LogString& value)
74
0
{
75
0
  if (StringHelper::equalsIgnoreCase(option,
76
0
      LOG4CXX_STR("MININDEX"),
77
0
      LOG4CXX_STR("minindex")))
78
0
  {
79
0
    priv->minIndex = OptionConverter::toInt(value, 1);
80
0
  }
81
0
  else if (StringHelper::equalsIgnoreCase(option,
82
0
      LOG4CXX_STR("MAXINDEX"),
83
0
      LOG4CXX_STR("maxindex")))
84
0
  {
85
0
    priv->maxIndex = OptionConverter::toInt(value, 7);
86
0
  }
87
0
  else if (StringHelper::equalsIgnoreCase(option,
88
0
      LOG4CXX_STR("THROWIOEXCEPTIONONFORKFAILURE"),
89
0
      LOG4CXX_STR("throwioexceptiononforkfailure")))
90
0
  {
91
0
    priv->throwIOExceptionOnForkFailure = OptionConverter::toBoolean(value, true);
92
0
  }
93
0
  else
94
0
  {
95
0
    RollingPolicyBase::setOption(option, value);
96
0
  }
97
0
}
98
99
/**
100
 * {@inheritDoc}
101
 */
102
void FixedWindowRollingPolicy::activateOptions( LOG4CXX_ACTIVATE_OPTIONS_FORMAL_PARAMETERS )
103
0
{
104
0
  priv->activateOptions(getFormatSpecifiers());
105
106
0
  if (priv->maxIndex < priv->minIndex)
107
0
  {
108
0
    LogLog::warn(
109
0
      LOG4CXX_STR("MaxIndex  cannot be smaller than MinIndex."));
110
0
    priv->maxIndex = priv->minIndex;
111
0
  }
112
113
0
  if ((priv->maxIndex - priv->minIndex) > MAX_WINDOW_SIZE)
114
0
  {
115
0
    LogLog::warn(LOG4CXX_STR("Large window sizes are not allowed."));
116
0
    priv->maxIndex = priv->minIndex + MAX_WINDOW_SIZE;
117
0
  }
118
119
0
  PatternConverterPtr itc = getIntegerPatternConverter();
120
121
0
  if (itc == NULL)
122
0
  {
123
0
    throw IllegalStateException();
124
0
  }
125
0
}
126
127
/**
128
 * {@inheritDoc}
129
 */
130
RolloverDescriptionPtr FixedWindowRollingPolicy::initialize( LOG4CXX_ROLLING_POLICY_INITIALIZE_FORMAL_PARAMETERS )
131
0
{
132
0
  LogString newActiveFile(currentActiveFile);
133
0
  priv->explicitActiveFile = false;
134
135
0
  if (currentActiveFile.length() > 0)
136
0
  {
137
0
    priv->explicitActiveFile = true;
138
0
    newActiveFile = currentActiveFile;
139
0
  }
140
141
0
  if (!priv->explicitActiveFile)
142
0
  {
143
0
    LogString buf;
144
0
    ObjectPtr obj = std::make_shared<Integer>(priv->minIndex);
145
0
    formatFileName(obj, buf);
146
0
    newActiveFile = buf;
147
0
  }
148
149
0
  ActionPtr noAction;
150
151
0
  return std::make_shared<RolloverDescription>(newActiveFile, append, noAction, noAction);
152
0
}
153
154
/**
155
 * {@inheritDoc}
156
 */
157
RolloverDescriptionPtr FixedWindowRollingPolicy::rollover( LOG4CXX_ROLLING_POLICY_ROLLOVER_FORMAL_PARAMETERS )
158
0
{
159
0
  RolloverDescriptionPtr desc;
160
161
0
  if (priv->maxIndex < 0)
162
0
  {
163
0
    return desc;
164
0
  }
165
166
0
  int purgeStart = priv->minIndex;
167
168
0
  if (!priv->explicitActiveFile)
169
0
  {
170
0
    purgeStart++;
171
0
  }
172
173
0
  if (!purge(purgeStart, priv->maxIndex))
174
0
  {
175
0
    return desc;
176
0
  }
177
178
0
  LogString buf;
179
0
  ObjectPtr obj = std::make_shared<Integer>(purgeStart);
180
0
  formatFileName(obj, buf);
181
182
0
  LogString renameTo(buf);
183
0
  LogString compressedName(renameTo);
184
0
  ActionPtr compressAction ;
185
186
0
  if(getCreateIntermediateDirectories()){
187
0
    File compressedFile(compressedName);
188
0
    File compressedParent (compressedFile.getParent());
189
0
    compressedParent.mkdirs();
190
0
  }
191
192
0
  if (StringHelper::endsWith(renameTo, LOG4CXX_STR(".gz")))
193
0
  {
194
0
    renameTo.resize(renameTo.size() - 3);
195
0
    GZCompressActionPtr comp = std::make_shared<GZCompressAction>(
196
0
          File().setPath(renameTo),
197
0
          File().setPath(compressedName),
198
0
          true);
199
0
    comp->setThrowIOExceptionOnForkFailure(priv->throwIOExceptionOnForkFailure);
200
0
    compressAction = comp;
201
0
  }
202
0
  else if (StringHelper::endsWith(renameTo, LOG4CXX_STR(".zip")))
203
0
  {
204
0
    renameTo.resize(renameTo.size() - 4);
205
0
    ZipCompressActionPtr comp = std::make_shared<ZipCompressAction>(
206
0
          File().setPath(renameTo),
207
0
          File().setPath(compressedName),
208
0
          true);
209
0
    comp->setThrowIOExceptionOnForkFailure(priv->throwIOExceptionOnForkFailure);
210
0
    compressAction = comp;
211
0
  }
212
213
0
  auto renameAction = std::make_shared<FileRenameAction>(
214
0
        File().setPath(currentActiveFile),
215
0
        File().setPath(renameTo),
216
0
        false);
217
218
0
  desc = std::make_shared<RolloverDescription>(
219
0
        currentActiveFile,  append,
220
0
        renameAction,       compressAction);
221
222
0
  return desc;
223
0
}
224
225
/**
226
 * Get index of oldest log file to be retained.
227
 * @return index of oldest log file.
228
 */
229
int FixedWindowRollingPolicy::getMaxIndex() const
230
0
{
231
0
  return priv->maxIndex;
232
0
}
233
234
/**
235
 * Get index of most recent log file.
236
 * @return index of oldest log file.
237
 */
238
int FixedWindowRollingPolicy::getMinIndex() const
239
0
{
240
0
  return priv->minIndex;
241
0
}
242
243
244
/**
245
 * Purge and rename old log files in preparation for rollover
246
 * @param lowIndex low index
247
 * @param highIndex high index.  Log file associated with high
248
 * index will be deleted if needed.
249
 * @return true if purge was successful and rollover should be attempted.
250
 */
251
bool FixedWindowRollingPolicy::purge(int lowIndex, int highIndex) const
252
0
{
253
0
  int suffixLength = 0;
254
255
0
  std::vector<FileRenameActionPtr> renames;
256
0
  LogString buf;
257
0
  ObjectPtr obj = std::make_shared<Integer>(lowIndex);
258
0
  formatFileName(obj, buf);
259
260
0
  LogString lowFilename(buf);
261
262
0
  if (StringHelper::endsWith(lowFilename, LOG4CXX_STR(".gz")))
263
0
  {
264
0
    suffixLength = 3;
265
0
  }
266
0
  else if (StringHelper::endsWith(lowFilename, LOG4CXX_STR(".zip")))
267
0
  {
268
0
    suffixLength = 4;
269
0
  }
270
271
0
  for (int i = lowIndex; i <= highIndex; i++)
272
0
  {
273
0
    File toRenameCompressed;
274
0
    toRenameCompressed.setPath(lowFilename);
275
0
    File toRenameBase;
276
0
    toRenameBase.setPath(lowFilename.substr(0, lowFilename.length() - suffixLength));
277
0
    File* toRename = &toRenameCompressed;
278
0
    bool isBase = false;
279
0
    bool exists = toRenameCompressed.exists();
280
281
0
    if (suffixLength > 0)
282
0
    {
283
0
      if (exists)
284
0
      {
285
0
        if (toRenameBase.exists())
286
0
        {
287
0
          toRenameBase.deleteFile();
288
0
        }
289
0
      }
290
0
      else
291
0
      {
292
0
        toRename = &toRenameBase;
293
0
        exists = toRenameBase.exists();
294
0
        isBase = true;
295
0
      }
296
0
    }
297
298
0
    if (exists)
299
0
    {
300
      //
301
      //    if at upper index then
302
      //        attempt to delete last file
303
      //        if that fails then abandon purge
304
0
      if (i == highIndex)
305
0
      {
306
0
        if (!toRename->deleteFile())
307
0
        {
308
0
          return false;
309
0
        }
310
311
0
        break;
312
0
      }
313
314
      //
315
      //   if intermediate index
316
      //     add a rename action to the list
317
0
      buf.erase(buf.begin(), buf.end());
318
0
      obj = std::make_shared<Integer>(i + 1);
319
0
      formatFileName(obj, buf);
320
321
0
      LogString highFilename(buf);
322
0
      LogString renameTo(highFilename);
323
324
0
      if (isBase)
325
0
      {
326
0
        renameTo =
327
0
          highFilename.substr(0, highFilename.length() - suffixLength);
328
0
      }
329
330
0
      renames.push_back(std::make_shared<FileRenameAction>(*toRename, File().setPath(renameTo), true));
331
0
      lowFilename = highFilename;
332
0
    }
333
0
    else
334
0
    {
335
0
      break;
336
0
    }
337
0
  }
338
339
  //
340
  //   work renames backwards
341
  //
342
0
  for (std::vector<FileRenameActionPtr>::reverse_iterator iter = renames.rbegin();
343
0
    iter != renames.rend();
344
0
    iter++)
345
0
  {
346
0
    auto& action = *iter;
347
0
    try
348
0
    {
349
0
      if (!action->execute())
350
0
      {
351
0
        return false;
352
0
      }
353
0
    }
354
0
    catch (const std::exception& ex)
355
0
    {
356
0
      LogLog::warn(action->getName() + LOG4CXX_STR(" raised the following exception"), ex);
357
358
0
      return false;
359
0
    }
360
0
  }
361
362
0
  return true;
363
0
}
364
#if LOG4CXX_ABI_VERSION <= 15
365
bool FixedWindowRollingPolicy::purge(int lowIndex, int highIndex, helpers::Pool& pool) const
366
0
{
367
0
  return purge(lowIndex, highIndex);
368
0
}
369
#endif
370
371
#define RULES_PUT(spec, cls) \
372
0
  specs.insert(PatternMap::value_type(LogString(LOG4CXX_STR(spec)), (PatternConstructor) cls ::newInstance))
373
374
375
LOG4CXX_NS::pattern::PatternMap FixedWindowRollingPolicy::getFormatSpecifiers() const
376
0
{
377
0
  PatternMap specs;
378
0
  RULES_PUT("i", IntegerPatternConverter);
379
0
  RULES_PUT("index", IntegerPatternConverter);
380
0
  return specs;
381
0
}