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
送信側(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); } }