<|start_filename|>examples/log4cplus/example.cpp<|end_filename|>
#include <crow/crow.hpp>
#include <crow/integrations/log4cplus.hpp>
#include <log4cplus/log4cplus.h>

using crow = nlohmann::crow;

int main()
{
    // init log4cplus and create a logger
    log4cplus::Initializer initializer;
    log4cplus::Logger test = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("test"));

    // create a Crow client
    crow crow_client("https://fad7ed01056940969a519aba36dc0b2f:3787b21e465845a09d781ab9eb048ae7@sentry.io/1253079");

    log4cplus::SharedAppenderPtr append(new nlohmann::crow_integrations::log4cplus_appender(crow_client));
    test.addAppender(append);

    LOG4CPLUS_TRACE(test, "this is a trace message");
    LOG4CPLUS_DEBUG(test, "this is a debug message");
    LOG4CPLUS_INFO(test, "this is an info message");
    LOG4CPLUS_WARN(test, "this is a warning message");
    LOG4CPLUS_ERROR(test, "this is an error message");
    LOG4CPLUS_FATAL(test, "this is a fatal message");
}


<|start_filename|>tests/uncaught_exception.cpp<|end_filename|>
#include <cassert>
#include <exception>
#include <crow/crow.hpp>

using crow = nlohmann::crow;

crow* client = nullptr;

// a termination handler that checks the state of the messages sent to Sentry
void my_termination_handler()
{
    std::string last_id = client->get_last_event_id();
    const bool success = not last_id.empty();
    delete client;
    std::exit(success ? 0 : 1);
}

int main()
{
    // register our checking termination handler
    std::set_terminate(my_termination_handler);

    // define a client and install the handlers
    client = new crow("http://abc:def@127.0.0.1:5000/1");
    client->install_handler();

    // throw an uncaught exception
    throw std::runtime_error("oops!");
}


<|start_filename|>examples/integration/subdirectory/example.cpp<|end_filename|>
#include <crow/crow.hpp>

using nlohmann::crow;

int main()
{
    crow client("http://abc:cde@sentry.io/42");

    client.add_breadcrumb("this is a breadcrumb");
    client.capture_message("this is a message");
}


<|start_filename|>include/crow/integrations/loggers.hpp<|end_filename|>
/*
 _____ _____ _____ _ _ _
|     | __  |     | | | |  Crow - a Sentry client for C++
|   --|    -|  |  | | | |  version 0.0.6
|_____|__|__|_____|_____|  https://github.com/nlohmann/crow

Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2018 <NAME> <http://nlohmann.me>.

Permission is hereby  granted, free of charge, to any  person obtaining a copy
of this software and associated  documentation files (the "Software"), to deal
in the Software  without restriction, including without  limitation the rights
to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#ifndef NLOHMANN_CROW_LOGGERS_HPP
#define NLOHMANN_CROW_LOGGERS_HPP

/*!
 * @file loggers.hpp
 * @brief common types for logger integrations
 */

namespace nlohmann
{
/*!
 * @brief integrations of Crow into other frameworks
 */
namespace crow_integrations
{

/*!
 * @brief different actions to be executed for a log event
 * @since 0.0.4
 */
enum log_action
{
    message_fatal,       ///< send a message with level "fatal"
    message_error,       ///< send a message with level "error"
    message_warning,     ///< send a message with level "warning"
    message_info,        ///< send a message with level "info"
    message_debug,       ///< send a message with level "debug"
    breadcrumb_fatal,    ///< add a breadcrumb with level "fatal"
    breadcrumb_error,    ///< add a breadcrumb with level "error"
    breadcrumb_warning,  ///< add a breadcrumb with level "warning"
    breadcrumb_info,     ///< add a breadcrumb with level "info"
    breadcrumb_debug,    ///< add a breadcrumb with level "debug"
    ignore               ///< do nothing
};

/*!
 * @brief get Sentry level for each log action

 * @param action log action
 * @return string representation of Sentry level

 * @since 0.0.4
 */
const char* log_action_level(const log_action action) noexcept
{
    switch (action)
    {
        case message_fatal:
        case breadcrumb_fatal:
            return "fatal";
        case message_error:
        case breadcrumb_error:
            return "error";
        case message_warning:
        case breadcrumb_warning:
            return "warning";
        case message_info:
        case breadcrumb_info:
            return "info";
        case message_debug:
        case breadcrumb_debug:
            return "debug";
        default:
            return "";
    }
}

}
}

#endif


<|start_filename|>include/crow/crow.hpp<|end_filename|>
/*
 _____ _____ _____ _ _ _
|     | __  |     | | | |  Crow - a Sentry client for C++
|   --|    -|  |  | | | |  version 0.0.6
|_____|__|__|_____|_____|  https://github.com/nlohmann/crow

Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2018 <NAME> <http://nlohmann.me>.

Permission is hereby  granted, free of charge, to any  person obtaining a copy
of this software and associated  documentation files (the "Software"), to deal
in the Software  without restriction, including without  limitation the rights
to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/*!
 * @file crow.hpp
 * @brief main header for Crow
 */

#ifndef NLOHMANN_CROW_HPP
#define NLOHMANN_CROW_HPP

#include <vector> // vector
#include <future> // future
#include <mutex> // mutex
#include <string> //string
#include <thirdparty/json/json.hpp>

using json = nlohmann::json;

/*!
 * @brief namespace for Niels Lohmann
 */
namespace nlohmann
{
/*!
 * @brief a C++ client for Sentry
 */
class crow
{
  public:
    /*!
     * @brief create a client
     *
     * @param[in] dsn the DNS string
     * @param[in] context an optional attributes object
     * @param[in] sample_rate the sample rate (0.0 .. 1.0, default: 1.0)
     * @param[in] install_handlers whether to install a termination handler (default: off)
     *
     * @throw std::invalid_argument if DNS string is invalid
     * @throw std::invalid_argument if context object contains invalid key
     *
     * @note If @a dns is empty, the client is disabled.
     *
     * @note
     * In case @a install_handlers is set to `true` (default), the currently
     * installed termination handler is replaced by a new termination handler
     * that first reports possibly uncaught exceptions and then executes the
     * previously installed termination handler. Note that termination
     * handlers installed after creating this client would override this
     * termination behavior. The termination handler can be installed later
     * with function @ref install_handler().
     *
     * @since 0.0.1
     */
    explicit crow(const std::string& dsn,
                  const json& context = nullptr,
                  double sample_rate = 1.0,
                  bool install_handlers = false);

    /*!
     * @brief install termination handler to handle uncaught exceptions
     * @post uncaught exceptions are reported prior to executing existing termination handler
     *
     * @since 0.0.3
     */
    void install_handler();

    /*!
     * @name event capturing
     * @{
     */

    /*!
     * @brief capture a message
     *
     * @param[in] message the message to capture
     * @param[in] attributes an optional attributes object
     *
     * @throw std::invalid_argument if context object contains invalid key
     *
     * @since 0.0.1
     */
    void capture_message(const std::string& message,
                         const json& attributes = nullptr);
    /*!
     * @brief capture an exception
     *
     * @param[in] exception the passed exception
     * @param[in] context an optional context object
     * @param[in] handled whether the exception was handled and only reported
     *
     * @throw std::invalid_argument if context object contains invalid key
     *
     * @since 0.0.1, context added with 0.0.3
     */
    void capture_exception(const std::exception& exception,
                           const json& context = nullptr,
                           bool handled = true);

    /*!
     * @brief add a breadcrumb to the current context
     *
     * @param[in] message message for the breadcrumb
     * @param[in] attributes an optional attributes object
     *
     * @since 0.0.1
     */
    void add_breadcrumb(const std::string& message,
                        const json& attributes = nullptr);

    /*!
     * @brief return the id of the last reported event
     *
     * @return event id, or empty string, if no request has been made
     *
     * @since 0.0.2
     */
    std::string get_last_event_id() const;

    /*!
     * @}
     */

    /*!
     * @name context management
     * @{
     */

    /*!
     * @brief return current context
     *
     * @return current context
     *
     * @since 0.0.3
     */
    const json& get_context() const;

    /*!
     * @brief set the code release id
     *
     * @param[in] release release id to add to the main context
     *
     * @since 0.0.7
     */
    void set_release(const std::string& release);

    /*!
     * @brief add elements to the "user" context for future events
     *
     * @param[in] data data to add to the extra context
     *
     * @since 0.0.3
     */
    void add_user_context(const json& data);

    /*!
     * @brief add elements to the "tags" context for future events
     *
     * @param[in] data data to add to the extra context
     *
     * @since 0.0.3
     */
    void add_tags_context(const json& data);

    /*!
     * @brief add elements to the "request" context for future events
     *
     * @param[in] data data to add to the extra context
     *
     * @since 0.0.3
     */
    void add_request_context(const json& data);

    /*!
     * @brief add elements to the "extra" context for future events
     *
     * @param[in] data data to add to the extra context
     *
     * @since 0.0.3
     */
    void add_extra_context(const json& data);

    /*!
     * @brief add context information to payload for future events
     *
     * @param[in] context the context to add
     *
     * @note @a context must be an object; allowed keys are "user", "request", "extea", or "tags"
     * @throw std::invalid_argument if context object contains invalid key
     *
     * @since 0.0.3
     */
    void merge_context(const json& context);

    /*!
     * @brief reset context for future events
     *
     * @post context is in the same state as it was after construction
     *
     * @since 0.0.3
     */
    void clear_context();

    /*!
     * @}
     */

  private:
    /*!
     * @brief POST the payload to the Sentry sink URL
     *
     * @param[in] payload payload to send
     * @param[in] synchronous whether the payload should be sent immediately
     * @return result
     */
    std::string post(json payload) const;

    void enqueue_post();

    /*!
     * @brief termination handler that detects uncaught exceptions
     *
     * @post previously installed termination handler is executed
     *
     * @note The rethrowing of uncaught exceptions does not work with Microsoft Visual Studio 2017, see
     *       https://developercommunity.visualstudio.com/content/problem/135332/stdcurrent-exception-returns-null-in-a-stdterminat.html
     */
    static void new_termination_handler();

  private:
    /// the sample rate (as integer 0..100)
    const int m_sample_rate;

    /// whether the client is enabled
    const bool m_enabled = true;
    /// the public key to be used in requests
    std::string m_public_key;
    /// the secret key to be used in requests
    std::string m_secret_key;
    /// the URL to send events to
    std::string m_store_url;

    /// the payload of all events
    json m_payload = {};
    /// a mutex to make payload thread-safe
    std::mutex m_payload_mutex;

    /// a vector of POST jobs
    mutable std::vector<std::future<std::string>> m_jobs;
    /// a mutex to make m_jobs thread-safe
    mutable std::mutex m_jobs_mutex;
    /// a cache for the last event id
    mutable std::string m_last_event_id = "-1";
    /// whether a post has been made already
    bool m_posts = false;

    /// the termination handler installed before initializing the client
    std::terminate_handler existing_termination_handler = nullptr;
    /// a pointer to the last client (used for termination handling)
    static crow* m_client_that_installed_termination_handler;

    /// the maximal number of running jobs
    static constexpr std::size_t m_maximal_jobs = 10;
};

}

#endif


<|start_filename|>src/crow_utilities.cpp<|end_filename|>
/*
 _____ _____ _____ _ _ _
|     | __  |     | | | |  Crow - a Sentry client for C++
|   --|    -|  |  | | | |  version 0.0.6
|_____|__|__|_____|_____|  https://github.com/nlohmann/crow

Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2018 <NAME> <http://nlohmann.me>.

Permission is hereby  granted, free of charge, to any  person obtaining a copy
of this software and associated  documentation files (the "Software"), to deal
in the Software  without restriction, including without  limitation the rights
to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/*!
 * @file crow_utilities.cpp
 * @brief implementation of Crow helper functions
 */

#include <chrono>
#include <cstdlib>
#include <cstddef>
#include <cstring>
#include <ctime>
#include <typeinfo>
#include <src/crow_config.hpp>
#include <src/crow_utilities.hpp>

#ifndef NLOHMANN_CROW_MINGW
    #include <random>
#else
    #include <cstdlib> // for srand, rand
    #include <ctime> // for time
#endif

#ifdef NLOHMANN_CROW_HAVE_CXXABI_H
    #include <cxxabi.h> // for abi::__cxa_demangle
#endif

#ifdef NLOHMANN_CROW_HAVE_EXECINFO_H
    #include <execinfo.h> // for backtrace
#endif

#ifdef NLOHMANN_CROW_HAVE_DLFCN_H
    #include <dlfcn.h> // for dladdr
#endif

namespace nlohmann
{

namespace crow_utilities
{

// https://gist.github.com/fmela/591333
// This function produces a stack backtrace with demangled function & method names.
json get_backtrace(int skip)
{
    json result = json::array();

#if defined(NLOHMANN_CROW_HAVE_DLFCN_H) && defined(NLOHMANN_CROW_HAVE_EXECINFO_H)
    void* callstack[128];
    const int nMaxFrames = sizeof(callstack) / sizeof(callstack[0]);
    char buf[1024];
    int nFrames = backtrace(callstack, nMaxFrames);
    char** symbols = backtrace_symbols(callstack, nFrames);

    for (int i = skip; i < nFrames; i++)
    {
        Dl_info info;
        if (dladdr(callstack[i], &info) && info.dli_sname)
        {
            char* demangled = nullptr;
            int status = -1;
            if (info.dli_sname[0] == '_')
            {
#ifdef NLOHMANN_CROW_HAVE_CXXABI_H
                demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
#endif
            }

            const std::string function_name = (status == 0 ? demangled : info.dli_sname == nullptr ? symbols[i] : info.dli_sname);

            snprintf(buf, sizeof(buf), "%-3d %*p %s + %zd\n",
                     i, int(2 + sizeof(void*) * 2), callstack[i],
                     function_name.c_str(),
                     (char*) callstack[i] - (char*) info.dli_saddr);
            //std::cout << buf << std::endl;

            json entry;
            entry["function"] = function_name;

            if (not function_name.empty())
            {
                if (function_name.substr(0, 5) == "std::" or function_name.substr(0, 2) == "__")
                {
                    entry["in_app"] = false;
                }
            }

            result.push_back(entry);

            free(demangled);
        }
        else
        {
            snprintf(buf, sizeof(buf), "%-3d %*p %s\n",
                     i, int(2 + sizeof(void*) * 2), callstack[i], symbols[i]);
        }
    }
    free(symbols);
#endif

    return result;
}

std::string pretty_name(const char* type_id_name,
                        const bool only_module)
{
#ifdef NLOHMANN_CROW_HAVE_CXXABI_H
    int status;
    std::string result = abi::__cxa_demangle(type_id_name, nullptr, nullptr, &status);
#else
    std::string result = type_id_name;
#endif

    return only_module
           ? result.substr(0, result.find_first_of(':'))
           : result;
}

std::int64_t get_timestamp()
{
    const auto tp = std::chrono::system_clock::now();
    const auto dur = tp.time_since_epoch();
    return std::chrono::duration_cast<std::chrono::seconds>(dur).count();
}

std::string get_iso8601()
{
    std::time_t now;
    std::time(&now);
    char buf[sizeof "2011-10-08T07:07:09Z"];
    std::strftime(buf, sizeof buf, "%Y-%m-%dT%H:%M:%SZ", std::gmtime(&now));
    return buf;
}

int get_random_number(int lower, int upper)
{
#ifdef NLOHMANN_CROW_MINGW
    static bool init = false;
    if (not init)
    {
        init = true;
        std::srand(std::time(nullptr));
    }
    return std::rand() % upper + lower;
#else
    std::random_device random_device;
    std::default_random_engine random_engine(random_device());
    std::uniform_int_distribution<int> uniform_dist(lower, upper);
    return uniform_dist(random_engine);
#endif
}

std::string generate_uuid()
{
    std::string result(32, ' ');

    for (std::size_t i = 0; i < result.size(); ++i)
    {
        // the 12th character must be a '4'
        if (i == 12)
        {
            result[i] = '4';
        }
        else
        {
            // get a random number from 0..15
            const auto r = static_cast<char>(get_random_number(0, 15));
            if (r < 10)
            {
                result[i] = '0' + r;
            }
            else
            {
                result[i] = 'a' + r - static_cast<char>(10);
            }
        }
    }

    return result;
}

}
}

<|start_filename|>tests/livetest.cpp<|end_filename|>
#include <iostream>
#include <crow/crow.hpp>
#include <src/crow_config.hpp>

using crow = nlohmann::crow;

int main()
{
    crow c("https://fad7ed01056940969a519aba36dc0b2f:3787b21e465845a09d781ab9eb048ae7@sentry.io/1253079");
    std::cout << "created client" << std::endl;

    c.add_breadcrumb(__DATE__ " " __TIME__);
    std::cout << "added breadcrumb" << std::endl;

    const char* job_number = getenv("APPVEYOR_JOB_NUMBER");
    if (job_number != nullptr)
    {
        c.add_extra_context({{"job_number", job_number}});
        c.add_tags_context({{"ci", "appveyor"}});
        const char* build_number = getenv("APPVEYOR_BUILD_NUMBER");
        if (build_number)
        {
            c.add_extra_context({{"build_number", build_number}});
        }
    }
    else
    {
        job_number = getenv("TRAVIS_JOB_NUMBER");
        if (job_number)
        {
            c.add_extra_context({{"job_number", job_number}});
            c.add_tags_context({{"ci", "travis"}});
        }
    }

    c.capture_message(NLOHMANN_CROW_CXX);
    std::cout << "sent message" << std::endl;

    std::cout << "last event id: " << c.get_last_event_id() << std::endl;
}


<|start_filename|>include/crow/integrations/log4cplus.hpp<|end_filename|>
/*
 _____ _____ _____ _ _ _
|     | __  |     | | | |  Crow - a Sentry client for C++
|   --|    -|  |  | | | |  version 0.0.6
|_____|__|__|_____|_____|  https://github.com/nlohmann/crow

Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2018 <NAME> <http://nlohmann.me>.

Permission is hereby  granted, free of charge, to any  person obtaining a copy
of this software and associated  documentation files (the "Software"), to deal
in the Software  without restriction, including without  limitation the rights
to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#ifndef NLOHMANN_CROW_LOG4CPLUS_HPP
#define NLOHMANN_CROW_LOG4CPLUS_HPP

#include <string>
#include <unordered_map>
#include <crow/crow.hpp>
#include <crow/integrations/loggers.hpp>
#include <log4cplus/log4cplus.h>
#include <log4cplus/clogger.h>

/*!
 * @file log4cplus.hpp
 * @brief interface for the Log4cplus appender
 */

namespace nlohmann
{
namespace crow_integrations
{

/*!
 * @example log4cplus/example.cpp
 */

/*!
 * @brief appender for Log4cplus
 * @since 0.0.4
 */
class log4cplus_appender : public log4cplus::Appender
{
  public:
    /*!
     * @brief create the appender
     * @param[in] client the Crow client to use
     * @param[in] appender_name the name of the appender (used internally of Log4cplus, defaults to "sentry appender")
     * @param[in] config a configuration (see below)
     * @since 0.0.4
     */
    explicit log4cplus_appender(crow& client,
                                const std::string& appender_name = "sentry appender",
                                const std::unordered_map<log4cplus_loglevel_t, log_action>& config = std::unordered_map<log4cplus_loglevel_t, log_action>())
        : m_client(client)
    {
        setName(appender_name);
        m_log_actions[L4CP_FATAL_LOG_LEVEL] = log_action::message_fatal;
        m_log_actions[L4CP_ERROR_LOG_LEVEL] = log_action::message_error;
        m_log_actions[L4CP_WARN_LOG_LEVEL] = log_action::breadcrumb_warning;
        m_log_actions[L4CP_INFO_LOG_LEVEL] = log_action::breadcrumb_info;
        m_log_actions[L4CP_DEBUG_LOG_LEVEL] = log_action::breadcrumb_debug;
        m_log_actions[L4CP_TRACE_LOG_LEVEL] = log_action::breadcrumb_debug;

        for (const auto& config_entry : config)
        {
            m_log_actions[config_entry.first] = config_entry.second;
        }
    }

    /*!
     * @brief clean up appender state
     * @since 0.0.4
     */
    ~log4cplus_appender() override
    {
        // properly clean up appender
        destructorImpl();
    }

    /*!
     * @brief closing the appender
     * @since 0.0.4
     */
    void close() override {};

  protected:
    /*!
     * @brief the actual appender implementation
     * @param[in] event log event to append
     * @since 0.0.4
     */
    void append(const log4cplus::spi::InternalLoggingEvent& event) override
    {
        // look up action in configuration or use default action
        const auto lookup_action = m_log_actions.find(event.getLogLevel());
        const log_action action = (lookup_action != m_log_actions.end())
                                  ? lookup_action->second
                                  : message_warning;

        switch (action)
        {
            case message_fatal:
            case message_error:
            case message_warning:
            case message_info:
            case message_debug:
            {
                m_client.capture_message(event.getMessage(),
                {
                    {"logger", event.getLoggerName()},
                    {"level", log_action_level(action)},
                    {
                        "extra", {
                            {"location", event.getFile() + ":" + std::to_string(event.getLine())},
                            {"function", event.getFunction()}
                        }
                    }
                });
                return;
            }

            case breadcrumb_fatal:
            case breadcrumb_error:
            case breadcrumb_warning:
            case breadcrumb_info:
            case breadcrumb_debug:
            {
                m_client.add_breadcrumb(event.getMessage(),
                {
                    {"category", event.getLoggerName()},
                    {"level", log_action_level(action)},
                    {
                        "data", {
                            {"location", event.getFile() + ":" + std::to_string(event.getLine())},
                            {"function", event.getFunction()}
                        }
                    }
                });

                return;
            }

            case ignore:
                return;
        }
    }

  private:
    /// configuration of log actions per log level
    std::unordered_map<log4cplus_loglevel_t, log_action> m_log_actions;
    /// the associated Sentry client
    crow& m_client;
};


}
}

#endif


<|start_filename|>src/crow_utilities.hpp<|end_filename|>
/*
 _____ _____ _____ _ _ _
|     | __  |     | | | |  Crow - a Sentry client for C++
|   --|    -|  |  | | | |  version 0.0.6
|_____|__|__|_____|_____|  https://github.com/nlohmann/crow

Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2018 <NAME> <http://nlohmann.me>.

Permission is hereby  granted, free of charge, to any  person obtaining a copy
of this software and associated  documentation files (the "Software"), to deal
in the Software  without restriction, including without  limitation the rights
to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#ifndef NLOHMANN_CROW_UTILITIES_HPP
#define NLOHMANN_CROW_UTILITIES_HPP

/*!
 * @file crow_utilities.hpp
 * @brief helper functions for Crow
 */

#include <cstdint>
#include <string>
#include <thirdparty/json/json.hpp>

using json = nlohmann::json;

namespace nlohmann
{
/*!
 * @brief helper functions for Crow
 */
namespace crow_utilities
{

json get_backtrace(int skip = 1);

/*!
 * @brief return pretty type name
 * @param[in] type_id_name result of type_id().name()
 * @param[in] only_module whether only the module name should be returned
 * @return demangled prettified name
 */
std::string pretty_name(const char* type_id_name,
                        bool only_module = false);

/*!
 * @brief return a random integer
 * @param[in] lower lower bound
 * @param[in] upper upper bound
 * @return lower <= x <= upper
 *
 * @note The C++11 random implementation is broken in MinGW, so we need to fall back to std::rand().
 */
int get_random_number(int lower, int upper);

/*!
 * @brief get the seconds since epoch
 * @return seconds since epoch
 */
std::int64_t get_timestamp();

/*!
 * @brief get the current date and time as ISO 8601 string
 * @return ISO 8601 string
 */
std::string get_iso8601();

/*!
 * @brief generate a UUID4 without dashes
 * @return UUID4
 */
std::string generate_uuid();

}
}

#endif


<|start_filename|>tests/unittests.cpp<|end_filename|>
#define CATCH_CONFIG_MAIN

#include <thirdparty/catch/catch.hpp>
#include <crow/crow.hpp>
#include <src/crow_utilities.hpp>

using json = nlohmann::json;
using crow = nlohmann::crow;

json parse_msg(const std::string& raw);
json parse_msg(const std::string& raw)
{
    CAPTURE(raw);
    auto msg = json::parse(raw);

    CAPTURE(msg);
    CHECK(msg.at("event_id").is_string());
    CHECK(msg.at("timestamp").is_string());
    CHECK(msg.at("platform").is_string());

    CHECK(msg.at("sdk").at("name").is_string());
    CHECK(msg.at("sdk").at("version").is_string());

    return msg;
}

TEST_CASE("utilities")
{
    SECTION("get_timestamp")
    {
        auto x = nlohmann::crow_utilities::get_timestamp();
        CAPTURE(x);
        CHECK(x > 1533027000);
    }

    SECTION("get_iso8601")
    {
        auto x = nlohmann::crow_utilities::get_iso8601();
        CAPTURE(x);
        CHECK(x.size() == 20);
        CHECK(x[4] == '-');
        CHECK(x[7] == '-');
        CHECK(x[10] == 'T');
        CHECK(x[13] == ':');
        CHECK(x[16] == ':');
        CHECK(x[19] == 'Z');
        CHECK(x.substr(0, 2) == "20");
    }

    SECTION("generate_uuid")
    {
        auto x = nlohmann::crow_utilities::generate_uuid();
        CAPTURE(x);
        CHECK(x.size() == 32);
        CHECK(x[12] == '4');

        auto y = nlohmann::crow_utilities::generate_uuid();
        CHECK(x != y);
    }
}

TEST_CASE("DSN parsing")
{
    SECTION("valid DSN")
    {
        CHECK_NOTHROW(crow("http://abc:def@sentry.io/123"));
        CHECK_NOTHROW(crow("https://abc:def@sentry.io/123"));
    }

    SECTION("invalid DSN")
    {
        // missing protocol
        CHECK_THROWS_AS(crow("://abc:def@sentry.io/123"), std::invalid_argument);

        // unsupported protocol
        CHECK_THROWS_AS(crow("gopher://abc:def@sentry.io/123"), std::invalid_argument);

        // missing public key
        CHECK_THROWS_AS(crow("https://:def@sentry.io/123"), std::invalid_argument);

        // missing private key
        CHECK_THROWS_AS(crow("https://abc:@sentry.io/123"), std::invalid_argument);

        // missing public and private key
        CHECK_THROWS_AS(crow("https://sentry.io/123"), std::invalid_argument);

        // missing project
        CHECK_THROWS_AS(crow("https://abc:def@sentry.io"), std::invalid_argument);
        CHECK_THROWS_AS(crow("https://abc:def@sentry.io/"), std::invalid_argument);
    }
}

TEST_CASE("sample rate")
{
    SECTION("sample rate 0.0")
    {
        crow crow_client("http://abc:def@127.0.0.1:5000/1", nullptr, 0.0);
        crow_client.capture_message("message");

        // make sure no message was sent
        CHECK(crow_client.get_last_event_id().empty());
    }

    SECTION("sample rate 1.0")
    {
        crow crow_client("http://abc:def@127.0.0.1:5000/1", nullptr, 1.0);
        crow_client.capture_message("message");

        // make sure a message was sent
        CHECK(not crow_client.get_last_event_id().empty());
    }
}

TEST_CASE("creating messages")
{
    crow crow_client("http://abc:def@12172.16.17.32:5000/1");

    SECTION("capture_message")
    {
        SECTION("without payload")
        {
            std::string msg_string = "message text";
            crow_client.capture_message(msg_string);

            // check payload sent to Sentry
            auto msg = parse_msg(crow_client.get_last_event_id());
            CHECK(msg["message"] == msg_string);
        }
    }

    SECTION("capture_exception")
    {
        SECTION("marked as handled")
        {
            std::string ex_string = "exception text";
            crow_client.capture_exception(std::runtime_error(ex_string), nullptr, true);

            // check payload sent to Sentry
            auto msg = parse_msg(crow_client.get_last_event_id());
            CHECK(msg["exception"][0]["value"] == ex_string);
            CHECK(msg["exception"][0]["mechanism"]["handled"]);
        }

        SECTION("marked as unhandled")
        {
            std::string ex_string = "exception text";
            crow_client.capture_exception(std::runtime_error(ex_string), nullptr, false);

            // check payload sent to Sentry
            auto msg = parse_msg(crow_client.get_last_event_id());
            CHECK(msg["exception"][0]["value"] == ex_string);
            CHECK(not msg["exception"][0]["mechanism"]["handled"]);
        }
    }

    SECTION("add_breadcrumb")
    {
        const std::string msg1 = "breadcrumb 1";
        const std::string msg2 = "breadcrumb 2";
        const json data2 = {{"from", "origin"}, {"to", "destination"}};

        // add breadcrumbs
        crow_client.add_breadcrumb(msg1);
        crow_client.add_breadcrumb(msg2, {{"type", "navigation"}, {"level", "info"}, {"data", data2}});

        // capture message
        std::string msg_string = "message text";
        crow_client.capture_message(msg_string);

        // check payload sent to Sentry
        auto msg = parse_msg(crow_client.get_last_event_id());
        CHECK(msg["breadcrumbs"]["values"].size() == 2);
        CHECK(msg["breadcrumbs"]["values"][0]["message"] == msg1);
        CHECK(msg["breadcrumbs"]["values"][1]["message"] == msg2);
    }
}

TEST_CASE("job list")
{
    crow crow_client("http://abc:def@127.0.0.1:5000/1");
    crow_client.capture_message("message_1");
    crow_client.capture_message("message_2");
    crow_client.capture_message("message_3");
    crow_client.capture_message("message_4");
    crow_client.capture_message("message_5");
    crow_client.capture_message("message_6");
    crow_client.capture_message("message_7");
    crow_client.capture_message("message_8");
    crow_client.capture_message("message_9");
    crow_client.capture_message("message_10");
    crow_client.capture_message("message_11");
}

TEST_CASE("context")
{
    crow crow_client("http://abc:def@127.0.0.1:5000/1");

    SECTION("user context")
    {
        // set email
        const std::string email = "<EMAIL>";
        crow_client.add_user_context({{"email", email}});

        // capture message
        crow_client.capture_message("msg");

        // check payload sent to Sentry
        auto msg = parse_msg(crow_client.get_last_event_id());
        CHECK(msg["user"]["email"] == email);
    }

    SECTION("tags context")
    {
        // set tag
        const json tag = {{"tag", "value"}};
        crow_client.add_tags_context(tag);

        // capture message
        crow_client.capture_message("msg");

        // check payload sent to Sentry
        auto msg = parse_msg(crow_client.get_last_event_id());
        CHECK(msg["tags"] == tag);
    }

    SECTION("request context")
    {
        // set request context
        crow_client.add_request_context({{"url", "http://example.com"}, {"method", "GET"}});

        // capture message
        crow_client.capture_message("msg");

        // check payload sent to Sentry
        auto msg = parse_msg(crow_client.get_last_event_id());

        // check payload sent to Sentry
        CHECK(msg["request"]["url"] == "http://example.com");
        CHECK(msg["request"]["method"] == "GET");
    }

    SECTION("extra context")
    {
        // set extra context
        const json extra = {{"foo", "bar"}};
        crow_client.add_extra_context(extra);

        // capture message
        crow_client.capture_message("msg");

        // check payload sent to Sentry
        auto msg = parse_msg(crow_client.get_last_event_id());

        CHECK(msg["extra"] == extra);
    }

    SECTION("reset context")
    {
        auto previous_context = crow_client.get_context();

        crow_client.add_user_context({{"email", "<EMAIL>"}});
        crow_client.add_tags_context({{"tag", "value"}});
        crow_client.add_request_context({{"url", "http://example.com"}, {"method", "GET"}});
        crow_client.add_extra_context({{"foo", "bar"}});

        CHECK(crow_client.get_context() != previous_context);

        crow_client.clear_context();

        CHECK(crow_client.get_context() == previous_context);
    }
}


<|start_filename|>tests/server/server.js<|end_filename|>
const http = require('http');
const zlib = require('zlib');

http.createServer((request, response) => {
    let body = [];
    request.on('error', (err) => {
        console.error(err);
    }).on('data', (chunk) => {
        body.push(chunk);
    }).on('end', () => {
        if (request.headers['content-encoding'] == 'gzip') {
            body = zlib.gunzipSync(Buffer.concat(body)).toString();
        }
        else {
            body = Buffer.concat(body).toString();
        }
        response.setHeader('Content-Type', 'application/json');
        response.end('{"id":' + JSON.stringify(body) + '}')
    });
}).listen(5000, '127.0.0.1');


<|start_filename|>maintainer/Makefile<|end_filename|>
all:
	@echo pretty      - indent code
	@echo upload_docs - upload documentation
	@echo coverage    - create coverage report

pretty:
	astyle --style=allman --indent=spaces=4 --indent-modifiers \
	   --indent-switches --indent-preproc-block --indent-preproc-define \
	   --indent-col1-comments --pad-oper --pad-header --align-pointer=type \
	   --align-reference=type --add-brackets --convert-tabs --close-templates \
	   --lineend=linux --preserve-date --suffix=none --formatted --recursive \
	   "include/crow/*.hpp,cpp" "tests/*.cpp,hpp" "src/*.cpp,*.hpp"

upload_docs:
	mkdir build ; cd build ; cmake .. ; cmake --build . --target crow_documentation ; cd ..
	cd build/doc ; ../../doc/scripts/git-update-ghpages nlohmann/crow html
	open http://nlohmann.github.io/crow/

coverage:
	mkdir build ; cd build ; cmake .. -DCROW_CHECK_COVERAGE=ON ; cmake --build . ; cd ..
	cd build ; ctest ; cd ..
	cd build ; cmake --build . --target crow_coverage_report ; cd ..
	open build/coverage_report/index.html
