<commit_before>/* Copyright (c) 2010 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef RAMCLOUD_LOGGING_H
#define RAMCLOUD_LOGGING_H

#include "Common.h"

namespace RAMCloud {

class CodeLocation;

/**
 * A module for capturing "test log entries" to facilitate unit testing.
 *
 * TEST_LOG calls can be removed by disabling TESTING.  Further, test logging
 * can be run time toggled using enable() and disable() to prevent unit tests
 * which aren't interested in the test log from accumulating the log in RAM.
 *
 * The easiest interface is to simply instantiate Enable at the beginning of a
 * test method.
 *
 * Example:
 * \code
 * void
 * FooClass::methodToTest()
 * {
 *     TEST_LOG("log message");
 * }
 *
 * void
 * test()
 * {
 *     TestLog::Enable _;
 *
 *     foo->methodName();
 *
 *     CPPUNIT_ASSERT_EQUAL(
 *         "void RAMCloud::FooClass:methodToTest(): log message",
 *         TestLog::get());
 * }
 * \endcode
 *
 * TEST_LOG calls in deeper calls may be irrelevant to a specific unit test
 * so a predicate can be specified using setPredicate or as an argument to
 * the constructor of Enable to select only interesting test log entries.
 * See setPredicate() for more detail.
 */
namespace TestLog {
    void reset();
    void disable();
    void enable();
    string get();
    void log(const CodeLocation& where, const char* format, ...)
        __attribute__((format(gnu_printf, 2, 3)));
    void setPredicate(bool (*pred)(string));

    /**
     * Reset and enable the test log on construction, reset and disable it
     * on destruction.
     *
     * Allows one to instrument a function in an exception safe way with
     * test logging just by sticking one of these on the stack.
     */
    struct Enable {
        /// Reset and enable/disable the test log on construction/destruction.
        Enable()
        {
            enable();
        }

        /**
         * Reset and enable/disable the test log on construction/destruction
         * using a particular predicate to filter test log entries.
         *
         * \param[in] pred
         *      See setPredicate().
         */
        Enable(bool (*pred)(string))
        {
            setPredicate(pred);
            enable();
        }

        /// Reset and disable test logging automatically.
        ~Enable()
        {
            disable();
        }
    };
} // namespace RAMCloud::TestLog

} // namespace RAMCloud
#if TESTING
/**
 * Log an entry in the test log for use in unit tests.
 *
 * See RAMCloud::TestLog for examples on how to use this for testing.
 *
 * \param[in] format
 *      A printf-style format string for the message. It should not have a line
 *      break at the end.
 * \param[in] ...
 *      The arguments to the format string.
 */
#define TEST_LOG(format, ...) \
    RAMCloud::TestLog::log(HERE, format, ##__VA_ARGS__)
#else
#define TEST_LOG(format, ...)
#endif

namespace RAMCloud {

/**
 * The levels of verbosity for messages logged with #LOG.
 */
enum LogLevel {
    // Keep this in sync with logLevelNames defined inside _LOG.
    SILENT_LOG_LEVEL = 0,
    ERROR,
    WARNING,
    NOTICE,
    DEBUG,
    NUM_LOG_LEVELS // must be the last element in the enum
};

enum LogModule {
    DEFAULT_LOG_MODULE = 0,
    TRANSPORT_MODULE,
    NUM_LOG_MODULES // must be the last element in the enum
};

class Logger {
  public:
    explicit Logger(LogLevel level);

    void setLogLevel(LogModule, LogLevel level);
    void setLogLevel(LogModule, int level);
    void changeLogLevel(LogModule, int delta);

    void setLogLevels(LogLevel level);
    void setLogLevels(int level);
    void changeLogLevels(int delta);

    void logMessage(LogModule module, LogLevel level,
                    const CodeLocation& where,
                    const char* format, ...)
        __attribute__((format(printf, 5, 6)));
    std::string getMessage(LogModule module, LogLevel level,
                           const CodeLocation& where,
                           const char* format, ...)<commit_msg>Document guidelines for log levels<commit_after>/* Copyright (c) 2010 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef RAMCLOUD_LOGGING_H
#define RAMCLOUD_LOGGING_H

#include "Common.h"

namespace RAMCloud {

class CodeLocation;

/**
 * A module for capturing "test log entries" to facilitate unit testing.
 *
 * TEST_LOG calls can be removed by disabling TESTING.  Further, test logging
 * can be run time toggled using enable() and disable() to prevent unit tests
 * which aren't interested in the test log from accumulating the log in RAM.
 *
 * The easiest interface is to simply instantiate Enable at the beginning of a
 * test method.
 *
 * Example:
 * \code
 * void
 * FooClass::methodToTest()
 * {
 *     TEST_LOG("log message");
 * }
 *
 * void
 * test()
 * {
 *     TestLog::Enable _;
 *
 *     foo->methodName();
 *
 *     CPPUNIT_ASSERT_EQUAL(
 *         "void RAMCloud::FooClass:methodToTest(): log message",
 *         TestLog::get());
 * }
 * \endcode
 *
 * TEST_LOG calls in deeper calls may be irrelevant to a specific unit test
 * so a predicate can be specified using setPredicate or as an argument to
 * the constructor of Enable to select only interesting test log entries.
 * See setPredicate() for more detail.
 */
namespace TestLog {
    void reset();
    void disable();
    void enable();
    string get();
    void log(const CodeLocation& where, const char* format, ...)
        __attribute__((format(gnu_printf, 2, 3)));
    void setPredicate(bool (*pred)(string));

    /**
     * Reset and enable the test log on construction, reset and disable it
     * on destruction.
     *
     * Allows one to instrument a function in an exception safe way with
     * test logging just by sticking one of these on the stack.
     */
    struct Enable {
        /// Reset and enable/disable the test log on construction/destruction.
        Enable()
        {
            enable();
        }

        /**
         * Reset and enable/disable the test log on construction/destruction
         * using a particular predicate to filter test log entries.
         *
         * \param[in] pred
         *      See setPredicate().
         */
        Enable(bool (*pred)(string))
        {
            setPredicate(pred);
            enable();
        }

        /// Reset and disable test logging automatically.
        ~Enable()
        {
            disable();
        }
    };
} // namespace RAMCloud::TestLog

} // namespace RAMCloud
#if TESTING
/**
 * Log an entry in the test log for use in unit tests.
 *
 * See RAMCloud::TestLog for examples on how to use this for testing.
 *
 * \param[in] format
 *      A printf-style format string for the message. It should not have a line
 *      break at the end.
 * \param[in] ...
 *      The arguments to the format string.
 */
#define TEST_LOG(format, ...) \
    RAMCloud::TestLog::log(HERE, format, ##__VA_ARGS__)
#else
#define TEST_LOG(format, ...)
#endif

namespace RAMCloud {

/**
 * The levels of verbosity for messages logged with #LOG.
 */
enum LogLevel {
    // Keep this in sync with logLevelNames defined inside _LOG.
    SILENT_LOG_LEVEL = 0,
    /**
     * Bad stuff that shouldn't happen. The system broke its contract to users
     * in some way or some major assumption was violated.
     */
    ERROR,
    /**
     * Messages at the WARNING level indicate that, although something went
     * wrong or something unexpected happened, it was transient and
     * recoverable.
     */
    WARNING,
    /**
     * Somewhere in between WARNING and DEBUG...
     */
    NOTICE,
    /**
     * Messages at the DEBUG level don't necessarily indicate that anything
     * went wrong, but they could be useful in diagnosing problems.
     */
    DEBUG,
    NUM_LOG_LEVELS // must be the last element in the enum
};

enum LogModule {
    DEFAULT_LOG_MODULE = 0,
    TRANSPORT_MODULE,
    NUM_LOG_MODULES // must be the last element in the enum
};

class Logger {
  public:
    explicit Logger(LogLevel level);

    void setLogLevel(LogModule, LogLevel level);
    void setLogLevel(LogModule, int level);
    void changeLogLevel(LogModule, int delta);

    void setLogLevels(LogLevel level);
    void setLogLevels(int level);
    void changeLogLevels(int delta);

    void logMessage(LogModule module, LogLevel level,
                    const CodeLocation& where,
                    const char* format, ...)
        __attribute__((format(printf, 5, 6)));
    std::string getMessage(LogModule module, LogLevel level,
                           const CodeLocation& where,
                           const char* format, ...)
{'fraction_non_alphanumeric': 0.08676573252219008, 'fraction_numerical': 0.001994614540740002, 'mean_word_length': 2.6058971592952176, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4687688', 'n_tokens_mistral': 2771, 'n_tokens_neox': 2657, 'n_words': 1111}