C++で簡単なロガーを考えてみた

コードを見ればわかるはず

#include <stdarg.h>
#include <string>
#include <sstream>
#include <fstream>

class LogLevel
{
public:
    enum type
    {
        Info= 1,
        Debug,
        Warn,
        Error,
    };

    static std::string ToString(LogLevel::type logLevel)
    {
        switch (logLevel)
        {
        case LogLevel::Info:  return "INFO ";
        case LogLevel::Debug: return "DEBUG";
        case LogLevel::Warn:  return "WARN ";
        case LogLevel::Error: return "ERROR";
        default:              return "UNKNOWN";
        }
    }
};


class Logger
{
private:
    LogLevel::type  m_tatgetLogLevel;
    std::string     m_logFilePath;

public:

    static Logger* GetInstance()
    {
        static Logger instance;
        return &instance;
    }

    // 出力したいログレベルを設定します
    void SetLogLevel(const LogLevel::type& logLevel)
    {
        this->m_tatgetLogLevel = logLevel;
    }

    // 出力したいログファイルを設定します
    void SetLogFilePath(const char* logFilePath)
    {
        this->m_logFilePath = logFilePath;
    }

    void Write(const LogLevel::type& logLevel, const char* fileName, const char* funcName, const int lineNum, const char* format, ...)
    {
        char message[512] = { 0 };
        va_list args;

        va_start(args, format);
#ifdef _WIN32
        vsprintf_s(message, format, args);
#else
        vsprintf(message, format, args);
#endif
        this->write(logLevel, fileName, funcName, lineNum, message);
        va_end(args);
    }

    void Info(const char* const fileName, const char* const funcName, const int lineNum, const char* message) const
    {
        this->write(LogLevel::Info, fileName, funcName, lineNum, message);
    }

    void Debug(const char* const fileName, const char* const funcName, const int lineNum, const char* message) const
    {
        this->write(LogLevel::Debug, fileName, funcName, lineNum, message);
    }

    void Warn(const char* const fileName, const char* const funcName, const int lineNum, const char* message) const
    {
        this->write(LogLevel::Warn, fileName, funcName, lineNum, message);
    }

    void Error(const char* const fileName, const char* const funcName, const int lineNum, const char* message) const
    {
        this->write(LogLevel::Error, fileName, funcName, lineNum, message);
    }

private:

    // 
    Logger() : m_tatgetLogLevel(LogLevel::Info)
    {
        // ログファイル名を決めましょう
        this->m_logFilePath = "C:\\testlog.log";
    }

    void write(const LogLevel::type& logLevel, const char* fileName, const char* funcName, const int lineNum, const char* message) const
    {
        if (!this->isEnabled(logLevel))
            return;

        // ログを出力する処理
        std::ofstream ofs;
        ofs.open(this->m_logFilePath, std::ios::app);

        ofs << this->getDateTimeNow() << " "
            << "[" << LogLevel::ToString(logLevel) << "]"
            << "[" << fileName << "]"
            << "[" << funcName << "]"
            << "[" << lineNum << "]"
            << message
            << std::endl;

        ofs.close();
    }

    bool isEnabled(const LogLevel::type& logLevel) const
    {
        return this->m_tatgetLogLevel <= logLevel;
    }

    std::string getDateTimeNow() const
    {
        std::ostringstream oss;

        // 時刻を整形する処理

        return oss.str();
    }
};


#define LOG_LEVEL_SET(x)        Logger::GetInstance()->SetLogLevel(x);
#define LOG_FILE_PATH_SET(x)    Logger::GetInstance()->SetLogFilePath(x);

#ifdef _WIN32
#define LOG_INFO(format, ...)   Logger::GetInstance()->Write(LogLevel::Info,  __FILE__, __FUNCTION__, __LINE__, format, __VA_ARGS__);
#define LOG_DEBUG(format, ...)  Logger::GetInstance()->Write(LogLevel::Debug, __FILE__, __FUNCTION__, __LINE__, format, __VA_ARGS__);
#define LOG_WARN(format, ...)   Logger::GetInstance()->Write(LogLevel::Warn,  __FILE__, __FUNCTION__, __LINE__, format, __VA_ARGS__);
#define LOG_ERROR(format, ...)  Logger::GetInstance()->Write(LogLevel::Error, __FILE__, __FUNCTION__, __LINE__, format, __VA_ARGS__);
#else
#define LOG_INFO(format, ...)   Logger::GetInstance()->Write(LogLevel::Info,  __FILE__, __func__, __LINE__, format, __VA_ARGS__);
#define LOG_DEBUG(format, ...)  Logger::GetInstance()->Write(LogLevel::Debug, __FILE__, __func__, __LINE__, format, __VA_ARGS__);
#define LOG_WARN(format, ...)   Logger::GetInstance()->Write(LogLevel::Warn,  __FILE__, __func__, __LINE__, format, __VA_ARGS__);
#define LOG_ERROR(format, ...)  Logger::GetInstance()->Write(LogLevel::Error, __FILE__, __func__, __LINE__, format, __VA_ARGS__);
#endif

int main(int argc, char* argv[])
{
    LOG_INFO("info %d, %d--", 1, 2);
    LOG_DEBUG("debug--");
    LOG_WARN("warn %s--", "あいうえお");
    LOG_ERROR("error %s %d--", "abcde", 1000);

    // yyyy/mm/dd hh:mm:ss.000 [INFO ][XXXX\cpploggersample.cpp][main][157]info 1, 2--
    // yyyy/mm/dd hh:mm:ss.000 [DEBUG][XXXX\cpploggersample.cpp][main][158]debug--
    // yyyy/mm/dd hh:mm:ss.000 [WARN ][XXXX\cpploggersample.cpp][main][159]warn あいうえお--
    // yyyy/mm/dd hh:mm:ss.000 [ERROR][XXXX\cpploggersample.cpp][main][160]error abcde 1000--

    return 0;
}

ちょっと備忘録6

COPYDATASTRUCTを使ったC#C++への通信

送信側(CS)

private void SendTextMessage(string t)
{
    IntPtr hwnd = FindWindow(null, "SendMessageSampleCPP");
    if (hwnd == IntPtr.Zero)
        return;

    IntPtr buf_ptr = IntPtr.Zero;
    IntPtr cds_ptr = IntPtr.Zero;
    try
    {
        var buf = System.Text.Encoding.GetEncoding("shift_jis").GetBytes(t);
        buf_ptr = Marshal.AllocHGlobal(buf.Length);
        Marshal.Copy(buf, 0, buf_ptr, buf.Length);

        var cds = new COPYDATASTRUCT();
        cds.dwData = this.Handle;
        cds.cbData = (uint)buf.Length;
        cds.lpData = buf_ptr;

        cds_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(cds));
        Marshal.StructureToPtr(cds, cds_ptr, false);

        SendMessage(hwnd, WM_COPYDATA, IntPtr.Zero, cds_ptr);
    }
    finally
    {
        var free = new Action<IntPtr>(p => { if (p != IntPtr.Zero) Marshal.FreeHGlobal(p); });
        free(cds_ptr);
        free(buf_ptr);
    }

}

受信側(C++

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COPYDATA:
        {
            auto cds = (COPYDATASTRUCT *)lParam;
            char buf[MAX_PATH] = {};
            memcpy(buf, cds->lpData, cds->cbData);

            int i = 0;
        }
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

ちょっと備忘録6 C#でディレクトリのバックアップ

拡張子を指定してディレクトリのバックアップを作成するコード
正直、自力でやるよりもrobocopyとか使ったほうがいいと思う。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;

namespace MyBackup
{
    public partial class Form1 : Form
    {
        private BackgroundWorker bw = new BackgroundWorker();

        public Form1()
        {
            InitializeComponent();

            bw.WorkerReportsProgress = true;
            bw.WorkerSupportsCancellation = true;

            bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);

            //ProgressBarの最大値を100に設定
            progressBar1.Maximum = 100;
        }

        private void buttonExecute_Click(object sender, EventArgs e)
        {
            bw.RunWorkerAsync();
        }

        private void buttonCancel_Click(object sender, EventArgs e)
        {
            bw.CancelAsync();
        }

        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            var worker = (BackgroundWorker)sender;

            string srcDirLoot = @"c:\temp";
            string dstDirLoot = @"c:\work\test";

            // バックアップ対象のファイルの拡張子を指定する
            var srcfiles = getBackupFiles(srcDirLoot, new string[] { ".log" }).ToArray();
            int max = srcfiles.Length;
            int count = 0;

            foreach (string srcFileName in srcfiles)
            {
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }

                string dstFileName = srcFileName.Replace(srcDirLoot, dstDirLoot);
                string srcDir = Path.GetDirectoryName(srcFileName);
                string dstDir = Path.GetDirectoryName(dstFileName);

                if (!Directory.Exists(dstDir))
                {
                    // ディレクトリ作成
                    Directory.CreateDirectory(dstDir);
                    // 属性コピー
                    File.SetAttributes(dstDir, File.GetAttributes(srcDir));
                }

                File.Copy(srcFileName, dstFileName, true);

                double percent = (double)(count + 1) / (double)max * 100;
                worker.ReportProgress((int)percent);

                count++;
            }

        }

        private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;
        }

        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
                MessageBox.Show("キャンセルしました...");
            else
                MessageBox.Show("バックアップ完了!!");
        }

        public static IEnumerable<string> getBackupFiles(string srcDir, string[] searchPatterns)
        {
            var files = Directory.GetFiles(srcDir, "*.*", SearchOption.AllDirectories);
            var query = files.Where(file => searchPatterns.Any(pattern => file.ToLower().EndsWith(pattern)));

            return query;
        }

    }

}

ちょっと備忘録5

#define ARRAY_LENGTH(x) ((sizeof(x) / sizeof(x[0])))

char s_massage[][10] = { "a", "b", "cc" };
int s_array[] = { 1, 2, 3, 4, 5 };

int main(int argc, char* argv[])
{
    const char(&m)[ARRAY_LENGTH(s_massage)][ARRAY_LENGTH(s_massage[0])] = s_massage;
    for (int i = 0; i < ARRAY_LENGTH(m); i++)
    {
        printf("%s\n", m[i]);
    }

    const int(&p)[ARRAY_LENGTH(s_array)] = s_array;
    for (int i = 0; i < ARRAY_LENGTH(p); i++)
    {
        printf("%d\n", p[i]);
    }

    return 0;
}

ちょっと備忘録4

最近はC++が一番のお気に入り。
テンプレートメタとか面白いよね。こっそり仕事でも取り入れて見たりしています。
(うちの職場だと大っぴらにやると読めない人多数なので)

Cの#defineから.Net用の定義がうまいこと簡単かつ自動でできないかいなーとかぼんやり考えてます。

というか、全然整理する時間がとれない・・・

@echo off
rem 
rem send.bat %1 %2 %3 %4
rem 
rem %1 = 送信に使用する定義ファイル名
rem %2 = %1で指定したファイル内の送信データ番号
rem %3 = 送信先サブシステム番号
rem %4 = 送信先サービス番号
rem 

rem 送信処理
@echo on
echo %3 %4 %2 y 0 y | xxxxxxx.exe %1
@echo off

@echo on

ちょっと備忘録2

いつか整理します

public class HotKey
    : IDisposable
{
    public enum MOD_KEY : int
    {
        NONE = 0x0000,
        ALT = 0x0001,
        CONTROL = 0x0002,
        SHIFT = 0x0004,
    }

    private HotKeyForm form;

    public event EventHandler HotKeyPushEventHandler;

    public HotKey(MOD_KEY modKey, Keys key)
    {
        this.form = 
            new HotKeyForm(modKey, key,
                () =>
                {
                    var ev = this.HotKeyPushEventHandler;
                    if (ev != null)
                        ev(this, EventArgs.Empty);
                });
    }

    #region Dispose パターンの実装

    private bool disposed = false;

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposed)
            return;

        if (disposing)
        {
            // Free any other managed objects here.
            this.form.Dispose();
        }

        // Free any unmanaged objects here.
        //
        disposed = true;
    }

    ~HotKey()
    {
        this.Dispose(false);
    }

    #endregion

    private class HotKeyForm
        : Form
    {
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        extern static int RegisterHotKey(IntPtr HWnd, int ID, MOD_KEY MOD_KEY, Keys KEY);

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        extern static int UnregisterHotKey(IntPtr HWnd, int ID);

        private const int WM_HOTKEY = 0x0312;
        private int id;
        private Action action;

        public HotKeyForm(MOD_KEY modKey, Keys key, Action action)
        {
            this.action = action;
            for (int i = 0x0000; i <= 0xbfff; i++)
            {
                if (RegisterHotKey(this.Handle, i, modKey, key) != 0)
                {
                    id = i;
                    break;
                }
            }
        }

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);

            if (m.Msg == WM_HOTKEY)
            {
                if ((int)m.WParam == id)
                {
                    action();
                }
            }
        }

        protected override void Dispose(bool disposing)
        {
            UnregisterHotKey(this.Handle, id);
            base.Dispose(disposing);
        }

    }
}

ちょっと備忘録

public class UserInfo
    : System.IEquatable<UserInfo>
{
    public string UserName { get; private set; }
    public string MachineName { get; private set; }

    public UserInfo(string userName, string machineName)
    {
        this.UserName = userName;
        this.MachineName = machineName;
    }

    public bool Equals(UserInfo other)
    {
        if (Object.ReferenceEquals(other, null))
            return false;

        if (object.ReferenceEquals(this, other))
            return true;

        if (this.GetType() != other.GetType())
            return false;

        return (this.UserName == other.UserName)
            && (this.MachineName == other.MachineName);
    }

    public override bool Equals(object obj)
    {
        return this.Equals(obj as UserInfo);
    }

    public override int GetHashCode()
    {
        return this.UserName.GetHashCode() ^ this.MachineName.GetHashCode();
    }

    public override string ToString()
    {
        return string.Concat("ユーザー名:", this.UserName, "(", this.MachineName, ")");
    }

    public static bool operator ==(UserInfo lhs, UserInfo rhs)
    {
        if (Object.ReferenceEquals(lhs, null))
        {
            if (Object.ReferenceEquals(rhs, null))
                return true;
            else
                return false;
        }

        return lhs.Equals(rhs);
    }

    public static bool operator !=(UserInfo lhs, UserInfo rhs)
    {
        return !(lhs == rhs);
    }

}