// ball_logfilecleanerutil.h                                          -*-C++-*-
#ifndef INCLUDED_BALL_LOGFILECLEANERUTIL
#define INCLUDED_BALL_LOGFILECLEANERUTIL

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a utility class for removing log files.
//
//@CLASSES:
//  ball::LogFileCleanerUtil: utility class for removing log files
//
//@SEE_ALSO: ball_fileobserver2, balb_filecleanerconfiguration
//
//@DESCRIPTION: This component defines a 'struct', 'ball::LogFileCleanerUtil',
// that provides utility functions for converting log file patterns used by
// 'ball' file observers into filesystem patterns and installing a custom
// rotation callback into file observers to perform log file cleanup.
//
///Log Filename Pattern
///--------------------
// The 'ball' file observers allow the use of '%'-escape sequences to specify
// log filenames.  The recognized sequences are as follows:
//..
//  %Y - current year (four digits with leading zeros)
//  %M - current month (two digits with leading zeros)
//  %D - current day (two digits with leading zeros)
//  %h - current hour (two digits with leading zeros)
//  %m - current minute (two digits with leading zeros)
//  %s - current second (two digits with leading zeros)
//  %T - current datetime, equivalent to "%Y%M%D_%h%m%s"
//  %p - process Id
//..
//
///Log Filename Pattern Conversion Rules
///-------------------------------------
// The 'logPatternToFilePattern' conversion function does the following:
//
// * Every recognized '%'-escape sequence is converted to '*'.
//
// * Successive '%'-escape sequences without any separator between them are
//   collapsed into a single '*'.
//
// * "%%" is converted into a single '%'.
//
// * All unrecognized '%'-escape sequences and characters are passed to
//   output as-is.
//
// * A single '*' is appended to the converted pattern when it does not
//   terminate with '*'.  (This is necessary for capturing rotated log files.)
//
//..
//  -------------------+---------------
//   Log File Pattern  | File Pattern
//  -------------------+---------------
//   "a.log"           | "a.log*"
//   "a.log.%T"        | "a.log.*"
//   "a.log.%Y"        | "a.log.*"
//   "a.log.%Y%M%D"    | "a.log.*"
//   "a.%T.log"        | "a.*.log*"
//  -------------------+---------------
//..
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Basic Usage
/// - - - - - - - - - - -
// The following snippets of code illustrate the basic usage of
// 'ball::LogFileCleanerUtil'.
//
// Suppose that the application was set up to do its logging using one of the
// 'ball' file observers (see 'ball_fileobserver2') with the following log
// pattern:
//..
//  const char *appLogPattern = "/var/log/myApp/log%T";
//..
// First, we need to convert the log filename pattern to the pattern that can
// be used for filename matching on the filesystem:
//..
//  bsl::string fileNamePattern;
//  ball::LogFileCleanerUtil::logPatternToFilePattern(&fileNamePattern,
//                                                    appLogPattern);
//..
// Finally, we test the resulting file pattern:
//..
//  assert("/var/log/myApp/log*" == fileNamePattern);
//..
///Example 2: Cleaning Log Files On File Rotation
/// - - - - - - - - - - - - - - - - - - - - - - -
// The following snippets of code illustrate how the application can implement
// automatic log file cleanup from the observer's file rotation callback.
//
// Suppose that the application was set up to do its logging using one of the
// file observers (see 'ball_fileobserver2') with the following log pattern:
//..
//  const char *appLogPattern = "/var/log/myApp/log%T";
//..
// First, we need to convert the log filename pattern to the pattern that can
// be used for filename matching on the filesystem:
//..
//  bsl::string fileNamePattern;
//  ball::LogFileCleanerUtil::logPatternToFilePattern(&fileNamePattern,
//                                                    appLogPattern);
//..
// Then, we create a configuration for the file cleaner utility.  The sample
// configuration below instructs the file cleaner to remove all log files that
// match the specified file pattern and are older than a week, but to keep at
// least 4 most recent log files:
//..
//  balb::FileCleanerConfiguration config(
//               fileNamePattern.c_str(),
//               bsls::TimeInterval(7 * bdlt::TimeUnitRatio::k_SECONDS_PER_DAY),
//               4);
//..
// Next, we create a file observer and enable file logging:
//..
//  ball::FileObserver2 observer;
//  observer.enableFileLogging(appLogPattern);
//..
// Finally, we use the utility function to install the file rotation callback
// that will invoke file cleanup with the specified configuration:
//..
//  ball::LogFileCleanerUtil::enableLogFileCleanup(&observer, config);
//..
// Note that the file cleanup will be performed immediately and on every log
// file rotation performed by the file observer.  Also note that this method
// overrides the file rotation callback currently installed in the file
// observer.

#include <balscm_version.h>

#include <balb_filecleanerconfiguration.h>
#include <balb_filecleanerutil.h>

#include <bdlf_bind.h>
#include <bdlf_placeholder.h>

#include <bsl_string.h>

namespace BloombergLP {
namespace ball {

                           // =========================
                           // struct LogFileCleanerUtil
                           // =========================

struct LogFileCleanerUtil {
    // This utility class provides functions for converting log file patterns
    // and for cleaning up log files based on a configuration.
  private:
    // PRIVATE CLASS METHODS
                        // ** default callback function **
    static
    void logFileCleanupOnRotationDefault(
                                 int,
                                 const bsl::string&,
                                 const balb::FileCleanerConfiguration& config);
        // Immediately call 'balb::FileCleanerUtil::removeFiles' with the
        // specified 'config'.

  public:
    // CLASS METHODS
    template <class t_OBSERVER>
    static
    void enableLogFileCleanup(
                               t_OBSERVER                            *observer,
                               const balb::FileCleanerConfiguration&  config);
        // Immediately call 'balb::FileCleanerUtil::removeFiles' with the
        // specified 'config' and then install an
        // 't_OBSERVER::OnFileRotationCallback' function into the specified
        // 'observer' that invokes 'removeFiles' synchronously on every log
        // file rotation.  The (template parameter) 't_OBSERVER' type must
        // provide concrete implementation of the 'ball::Observer' protocol,
        // have a 'setOnFileRotationCallback' method (see 'ball_fileobserver',
        // 'ball_fileobserver2', and 'ball_asyncfileobserver'), and define an
        // 'OnFileRotationCallback' type alias.  This method overrides the file
        // rotation callback currently installed in the observer (if any).

    static
    void logPatternToFilePattern(bsl::string             *filePattern,
                                 const bsl::string_view&  logPattern);
        // Substitute all occurrences of valid '%'-escape sequences in the
        // specified 'logPattern' with '*' and load the specified 'filePattern'
        // with the resulting string.  This utility function converts the log
        // patterns used by various file observers and supplied to their
        // 'enableFileLogging' method (see 'ball_fileobserver',
        // 'ball_fileobserver2', and 'ball_asyncfileobserver') to the file
        // pattern used by various utility functions to find the related
        // file(s) on the filesystem (see 'balb_filecleanerutil' and
        // 'balb_filecleanerconfiguration').
};

// ============================================================================
//                            INLINE DEFINITIONS
// ============================================================================

                           // -------------------------
                           // struct LogFileCleanerUtil
                           // -------------------------

// CLASS METHOD
template <class t_OBSERVER>
inline
void LogFileCleanerUtil::enableLogFileCleanup(
                               t_OBSERVER                            *observer,
                               const balb::FileCleanerConfiguration&  config)
{
    balb::FileCleanerUtil::removeFiles(config);

    typename t_OBSERVER::OnFileRotationCallback  rotationCallback =
        bdlf::BindUtil::bind(&logFileCleanupOnRotationDefault,
                             bdlf::PlaceHolders::_1,
                             bdlf::PlaceHolders::_2,
                             config);

    observer->setOnFileRotationCallback(rotationCallback);
}

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2017 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------