Skip to content

File Log.h

File List > Amplitude > IO > Log.h

Go to the documentation of this file

// Copyright (c) 2021-present Sparky Studios. All rights reserved.
//
// 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.

#pragma once

#ifndef _AM_IO_LOG_H
#define _AM_IO_LOG_H

#include <atomic>
#include <memory>
#include <mutex>

#include <SparkyStudios/Audio/Amplitude/Core/Common.h>
#include <SparkyStudios/Audio/Amplitude/Core/MPSCQueue.h>

#define amLogger SparkyStudios::Audio::Amplitude::Logger::GetLogger()

#define amLog(_level_, _message_, ...)                                                                                                     \
    if (amLogger != nullptr)                                                                                                               \
    {                                                                                                                                      \
        constexpr size_t bufferLen = 4096;                                                                                                 \
        char buffer[bufferLen];                                                                                                            \
        const int formatted = std::snprintf(buffer, bufferLen, _message_, ##__VA_ARGS__);                                                  \
        const size_t length =                                                                                                              \
            formatted < 0 ? 0 : (static_cast<size_t>(formatted) < bufferLen ? static_cast<size_t>(formatted) : bufferLen - 1);             \
        SparkyStudios::Audio::Amplitude::Logger::Emit(                                                                                     \
            SparkyStudios::Audio::Amplitude::eLogMessageLevel_##_level_, __FILE__, __LINE__, buffer, length);                              \
    }                                                                                                                                      \
    (void)0

#define amLogDebug(_message_, ...) amLog(Debug, _message_, ##__VA_ARGS__)

#define amLogInfo(_message_, ...) amLog(Info, _message_, ##__VA_ARGS__)

#define amLogWarning(_message_, ...) amLog(Warning, _message_, ##__VA_ARGS__)

#define amLogError(_message_, ...) amLog(Error, _message_, ##__VA_ARGS__)

#define amLogCritical(_message_, ...) amLog(Critical, _message_, ##__VA_ARGS__)

#define amLogSuccess(_message_, ...) amLog(Success, _message_, ##__VA_ARGS__)

namespace SparkyStudios::Audio::Amplitude
{
    enum eLogMessageLevel : AmUInt8
    {
        eLogMessageLevel_Debug = 0,

        eLogMessageLevel_Info = 1,

        eLogMessageLevel_Warning = 2,

        eLogMessageLevel_Error = 3,

        eLogMessageLevel_Critical = 4,

        eLogMessageLevel_Success = 5,
    };

    class AM_API_PUBLIC Logger
    {
    public:
        class AM_API_PUBLIC ScopedAudioThread
        {
        public:
            ScopedAudioThread();
            ~ScopedAudioThread();

            ScopedAudioThread(const ScopedAudioThread&) = delete;
            ScopedAudioThread& operator=(const ScopedAudioThread&) = delete;

        private:
            bool _previous;
        };

        static constexpr AmSize kMaxQueuedMessageLength = 256;

        Logger();

        virtual ~Logger();

        static void SetLogger(Logger* loggerInstance);

        static Logger* GetLogger();

        static void Emit(eLogMessageLevel level, const char* file, int line, const char* message, AmSize length);

        void Debug(const char* file, int line, const AmString& message);

        void Info(const char* file, int line, const AmString& message);

        void Warning(const char* file, int line, const AmString& message);

        void Error(const char* file, int line, const AmString& message);

        void Critical(const char* file, int line, const AmString& message);

        void Success(const char* file, int line, const AmString& message);

        void Write(eLogMessageLevel level, const char* file, int line, const char* message, AmSize length);

        void Flush();

    protected:
        virtual void Log(eLogMessageLevel level, const char* file, int line, const AmString& message) = 0;

    private:
        struct LogEntry
        {
            eLogMessageLevel level;
            int line;
            const char* file;
            AmUInt32 length;
            char message[kMaxQueuedMessageLength + 1];
        };

        static constexpr AmSize kQueueCapacity = 256;

        void Drain();

        std::unique_ptr<MPSCQueue<LogEntry, kQueueCapacity>> _logEntries;
        std::atomic<AmUInt32> _droppedEntries;
        std::recursive_mutex _writeMutex;
    };
} // namespace SparkyStudios::Audio::Amplitude

#endif // _AM_IO_LOG_H