Coverage Report

Created: 2025-07-01 06:08

/src/logging-log4cxx/src/main/cpp/fixedwindowrollingpolicy.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
#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(Pool& p)
103
0
{
104
0
  RollingPolicyBase::activateOptions(p);
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(
131
  const   LogString&  currentActiveFile,
132
  const   bool        append,
133
  Pool&       pool)
134
0
{
135
0
  LogString newActiveFile(currentActiveFile);
136
0
  priv->explicitActiveFile = false;
137
138
0
  if (currentActiveFile.length() > 0)
139
0
  {
140
0
    priv->explicitActiveFile = true;
141
0
    newActiveFile = currentActiveFile;
142
0
  }
143
144
0
  if (!priv->explicitActiveFile)
145
0
  {
146
0
    LogString buf;
147
0
    ObjectPtr obj = std::make_shared<Integer>(priv->minIndex);
148
0
    formatFileName(obj, buf, pool);
149
0
    newActiveFile = buf;
150
0
  }
151
152
0
  ActionPtr noAction;
153
154
0
  return std::make_shared<RolloverDescription>(newActiveFile, append, noAction, noAction);
155
0
}
156
157
/**
158
 * {@inheritDoc}
159
 */
160
RolloverDescriptionPtr FixedWindowRollingPolicy::rollover(
161
  const   LogString&  currentActiveFile,
162
  const   bool        append,
163
  Pool&       pool)
164
0
{
165
0
  RolloverDescriptionPtr desc;
166
167
0
  if (priv->maxIndex < 0)
168
0
  {
169
0
    return desc;
170
0
  }
171
172
0
  int purgeStart = priv->minIndex;
173
174
0
  if (!priv->explicitActiveFile)
175
0
  {
176
0
    purgeStart++;
177
0
  }
178
179
0
  if (!purge(purgeStart, priv->maxIndex, pool))
180
0
  {
181
0
    return desc;
182
0
  }
183
184
0
  LogString buf;
185
0
  ObjectPtr obj = std::make_shared<Integer>(purgeStart);
186
0
  formatFileName(obj, buf, pool);
187
188
0
  LogString renameTo(buf);
189
0
  LogString compressedName(renameTo);
190
0
  ActionPtr compressAction ;
191
192
0
  if(getCreateIntermediateDirectories()){
193
0
    File compressedFile(compressedName);
194
0
    File compressedParent (compressedFile.getParent(pool));
195
0
    compressedParent.mkdirs(pool);
196
0
  }
197
198
0
  if (StringHelper::endsWith(renameTo, LOG4CXX_STR(".gz")))
199
0
  {
200
0
    renameTo.resize(renameTo.size() - 3);
201
0
    GZCompressActionPtr comp = std::make_shared<GZCompressAction>(
202
0
          File().setPath(renameTo),
203
0
          File().setPath(compressedName),
204
0
          true);
205
0
    comp->setThrowIOExceptionOnForkFailure(priv->throwIOExceptionOnForkFailure);
206
0
    compressAction = comp;
207
0
  }
208
0
  else if (StringHelper::endsWith(renameTo, LOG4CXX_STR(".zip")))
209
0
  {
210
0
    renameTo.resize(renameTo.size() - 4);
211
0
    ZipCompressActionPtr comp = std::make_shared<ZipCompressAction>(
212
0
          File().setPath(renameTo),
213
0
          File().setPath(compressedName),
214
0
          true);
215
0
    comp->setThrowIOExceptionOnForkFailure(priv->throwIOExceptionOnForkFailure);
216
0
    compressAction = comp;
217
0
  }
218
219
0
  auto renameAction = std::make_shared<FileRenameAction>(
220
0
        File().setPath(currentActiveFile),
221
0
        File().setPath(renameTo),
222
0
        false);
223
224
0
  desc = std::make_shared<RolloverDescription>(
225
0
        currentActiveFile,  append,
226
0
        renameAction,       compressAction);
227
228
0
  return desc;
229
0
}
230
231
/**
232
 * Get index of oldest log file to be retained.
233
 * @return index of oldest log file.
234
 */
235
int FixedWindowRollingPolicy::getMaxIndex() const
236
0
{
237
0
  return priv->maxIndex;
238
0
}
239
240
/**
241
 * Get index of most recent log file.
242
 * @return index of oldest log file.
243
 */
244
int FixedWindowRollingPolicy::getMinIndex() const
245
0
{
246
0
  return priv->minIndex;
247
0
}
248
249
250
/**
251
 * Purge and rename old log files in preparation for rollover
252
 * @param lowIndex low index
253
 * @param highIndex high index.  Log file associated with high
254
 * index will be deleted if needed.
255
 * @return true if purge was successful and rollover should be attempted.
256
 */
257
bool FixedWindowRollingPolicy::purge(int lowIndex, int highIndex, Pool& p) const
258
0
{
259
0
  int suffixLength = 0;
260
261
0
  std::vector<FileRenameActionPtr> renames;
262
0
  LogString buf;
263
0
  ObjectPtr obj = std::make_shared<Integer>(lowIndex);
264
0
  formatFileName(obj, buf, p);
265
266
0
  LogString lowFilename(buf);
267
268
0
  if (lowFilename.compare(lowFilename.length() - 3, 3, LOG4CXX_STR(".gz")) == 0)
269
0
  {
270
0
    suffixLength = 3;
271
0
  }
272
0
  else if (lowFilename.compare(lowFilename.length() - 4, 4, LOG4CXX_STR(".zip")) == 0)
273
0
  {
274
0
    suffixLength = 4;
275
0
  }
276
277
0
  for (int i = lowIndex; i <= highIndex; i++)
278
0
  {
279
0
    File toRenameCompressed;
280
0
    toRenameCompressed.setPath(lowFilename);
281
0
    File toRenameBase;
282
0
    toRenameBase.setPath(lowFilename.substr(0, lowFilename.length() - suffixLength));
283
0
    File* toRename = &toRenameCompressed;
284
0
    bool isBase = false;
285
0
    bool exists = toRenameCompressed.exists(p);
286
287
0
    if (suffixLength > 0)
288
0
    {
289
0
      if (exists)
290
0
      {
291
0
        if (toRenameBase.exists(p))
292
0
        {
293
0
          toRenameBase.deleteFile(p);
294
0
        }
295
0
      }
296
0
      else
297
0
      {
298
0
        toRename = &toRenameBase;
299
0
        exists = toRenameBase.exists(p);
300
0
        isBase = true;
301
0
      }
302
0
    }
303
304
0
    if (exists)
305
0
    {
306
      //
307
      //    if at upper index then
308
      //        attempt to delete last file
309
      //        if that fails then abandon purge
310
0
      if (i == highIndex)
311
0
      {
312
0
        if (!toRename->deleteFile(p))
313
0
        {
314
0
          return false;
315
0
        }
316
317
0
        break;
318
0
      }
319
320
      //
321
      //   if intermediate index
322
      //     add a rename action to the list
323
0
      buf.erase(buf.begin(), buf.end());
324
0
      obj = std::make_shared<Integer>(i + 1);
325
0
      formatFileName(obj, buf, p);
326
327
0
      LogString highFilename(buf);
328
0
      LogString renameTo(highFilename);
329
330
0
      if (isBase)
331
0
      {
332
0
        renameTo =
333
0
          highFilename.substr(0, highFilename.length() - suffixLength);
334
0
      }
335
336
0
      renames.push_back(std::make_shared<FileRenameAction>(*toRename, File().setPath(renameTo), true));
337
0
      lowFilename = highFilename;
338
0
    }
339
0
    else
340
0
    {
341
0
      break;
342
0
    }
343
0
  }
344
345
  //
346
  //   work renames backwards
347
  //
348
0
  for (std::vector<FileRenameActionPtr>::reverse_iterator iter = renames.rbegin();
349
0
    iter != renames.rend();
350
0
    iter++)
351
0
  {
352
353
0
    try
354
0
    {
355
0
      if (!(*iter)->execute(p))
356
0
      {
357
0
        return false;
358
0
      }
359
0
    }
360
0
    catch (std::exception&)
361
0
    {
362
0
      LogLog::warn(LOG4CXX_STR("Exception during purge in RollingFileAppender"));
363
364
0
      return false;
365
0
    }
366
0
  }
367
368
0
  return true;
369
0
}
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
}