LogHelper

#pragma once

using namespace System;
using namespace System::Diagnostics;
using namespace System::Threading;

ref class Lock {
    Object^ m_pObject;
public:
    Lock(Object^ pObject) : m_pObject(pObject) {
        Monitor::Enter(m_pObject);
    }
    ~Lock() {
        Monitor::Exit(m_pObject);
    }
};

ref class LogHelper
{
private:
    const Object^ balanceLock = gcnew Object();
    TraceSource^ traceSource;
    property String^ LogName;
    property String^ LogFileDirectory;
    property String^ LogFilePath;
    property bool LogFileNameDateSuffix;
    property long ArchiveAboveSize;
    property int MaxArchiveFiles;

public:
    LogHelper(String^ logName, String^ fileDirectory, bool useDateSuffix, long archiveFileSize, int archiveFileQuantity, SourceLevels sourceLevels);
    void ArchiveLogFile(String^ logFilePath);
    void Flush();
    void WriteLog(TraceEventType eventType, String^ strLog);
    void WriteLog(TraceEventType eventType, Exception^ ex);

};


#include "pch.h"
#include "LogHelper.h"

using namespace System::IO;

LogHelper::LogHelper(String^ logName, String^ fileDirectory, bool useDateSuffix, long archiveFileSize, int archiveFileQuantity, SourceLevels sourceLevels)
{
    try
    {
        LogName = logName;
        LogFileDirectory = fileDirectory;
        LogFileNameDateSuffix = useDateSuffix;
        ArchiveAboveSize = archiveFileSize;
        MaxArchiveFiles = archiveFileQuantity;

        Directory::CreateDirectory(LogFileDirectory);
        if (LogFileNameDateSuffix)
        {
            LogFilePath = Path::Combine(LogFileDirectory, String::Format("{0}_{1:yyyy-MM-dd}.log", LogName, DateTime::Now));
        }
        else
        {
            LogFilePath = Path::Combine(LogFileDirectory, String::Format("{0}.log", LogName));
        }

        this->traceSource = gcnew TraceSource(LogName, sourceLevels);

        this->traceSource->Listeners->Remove("Default");
        if (traceSource->Listeners->Count == 0)
        {
            TextWriterTraceListener^ textWriterTraceListener = gcnew TextWriterTraceListener(LogFilePath, LogName + "Writer");
            textWriterTraceListener->TraceOutputOptions = TraceOptions::None;
            traceSource->Listeners->Add(textWriterTraceListener);
        }

    }
    catch (Exception^ ex)
    {
        throw;
    }
}

void LogHelper::ArchiveLogFile(String^ logFilePath)
{
    try
    {
        if (File::Exists(logFilePath))
        {
            long fileSize = (gcnew FileInfo(logFilePath))->Length;
            if (fileSize > ArchiveAboveSize)
            {
                if (traceSource != nullptr)
                {
                    traceSource->Close();
                }

                if (File::Exists(String::Format("{0}.0", logFilePath)))
                {
                    File::Delete(String::Format("{0}.0", logFilePath));
                }
                File::Move(logFilePath, String::Format("{0}.0", logFilePath));

                File::Delete(String::Format("{0}.{1}", logFilePath, MaxArchiveFiles));
                for (int i = MaxArchiveFiles; i > 0; i--)
                {
                    if (File::Exists(String::Format("{0}.{1}", logFilePath, i - 1)))
                    {
                        File::Move(String::Format("{0}.{1}", logFilePath, i - 1), String::Format("{0}.{1}", logFilePath, i));
                    }
                }
            }
        }
    }
    catch (Exception^ ex)
    {
    }
}

void LogHelper::Flush()
{
    if (traceSource != nullptr)
    {
        traceSource->Close();
    }
}

void LogHelper::WriteLog(TraceEventType eventType, String^ strLog)
{
    try
    {
        Lock lock(this);
        if (traceSource->Switch->ShouldTrace(eventType))
        {
            ArchiveLogFile(LogFilePath);
            for each (TraceListener ^ item in traceSource->Listeners)
            {
                item->WriteLine(String::Format("{0:yyyy-MM-ddTHH:mm:ss.fff} {1} {2}", DateTime::Now, eventType, strLog));
#if _DEBUG
                item->Flush();
#endif
            }
        }
    }
    catch (Exception^)
    {
    }
}

void LogHelper::WriteLog(TraceEventType eventType, Exception^ ex)
{
    try
    {
        Lock lock(this);
        if (traceSource->Switch->ShouldTrace(eventType))
        {
            ArchiveLogFile(LogFilePath);
            for each (TraceListener ^ item in traceSource->Listeners)
            {
                item->WriteLine(String::Format("{0:yyyy-MM-ddTHH:mm:ss.fff} {1} {2}", DateTime::Now, eventType, ex->Message));
                item->Flush();
            }
        }
    }
    catch (Exception^)
    {
    }
}

LogService

#pragma once
#include "LogHelper.h"

using namespace System;

ref class LogService
{
private:
    static Lazy<LogService^>^ lazy = gcnew Lazy<LogService^>(gcnew Func<LogService^>(GetInstance));
    static LogService^ GetInstance()
    {
        return gcnew LogService();
    }
    LogService();

    LogHelper^ logHelper;
    property String^ LogDirectory;
    void Init(String^ fileDirectory, long archiveFileSize, int archiveFileQuantity);

public:
    property static LogService^ Current
    {
        LogService^ get()
        {
            return lazy->Value;
        }
    }

    property LogHelper^ LogHelper
    {
    public:
        ::LogHelper^ get()
        {
            return logHelper;
        }

    private:
        void set(::LogHelper^ value)
        {
            logHelper = value;
        }
    }

    static String^ GetString(array<unsigned char>^ data);

    static String^ GetString(const CString& cstr);

};


#include "pch.h"
#include "LogService.h"

using namespace System::IO;

LogService::LogService()
{
    String^ logDirectory = gcnew String("C:\\ProgramData\\ABB\\PickMaster Twin\\PickMaster Twin Host\\PickMaster Operator\\Log\\CPP");
    Directory::CreateDirectory(logDirectory);
    Init(logDirectory, 10000000, 5);
}

void LogService::Init(String^ fileDirectory, long archiveFileSize, int archiveFileQuantity)
{
    if (LogHelper != nullptr)
    {
        return;
    }
    else
    {
        if (Directory::Exists(fileDirectory))
        {
            LogDirectory = fileDirectory;
            LogHelper = gcnew ::LogHelper("CPP", LogDirectory, false, 10000000, 5, SourceLevels::All);
        }
    }
}

String^ LogService::GetString(array<unsigned char>^ data)
{
    return System::Text::Encoding::ASCII->GetString(data);
}

String^ LogService::GetString(const CString& cstr)
{
    return gcnew String(cstr.GetString());
}

main

LogService::Current->LogHelper->WriteLog(TraceEventType::Information, "Test log message");