1 module appbase.utils.log;
2 
3 import core.sync.mutex;
4 import std.path : buildPath;
5 import std.conv : to;
6 import std.experimental.logger.core : LogLevel;
7 import std.experimental.logger.filelogger : FileLogger, CreateFolder;
8 import std.datetime;
9 import std.stdio : writeln;
10 
11 import appbase.utils.utility;
12 
13 /// file logger.
14 struct Logger
15 {
16     private __gshared Date today;
17     private __gshared FileLogger fl;
18  
19     private __gshared Mutex _mutex;
20 
21     private static this()
22     {
23         _mutex = new Mutex();
24     }
25 
26     /// write log to file.
27     static void write(string file = __FILE__, size_t line = __LINE__,
28         string funcName = __FUNCTION__,
29         string prettyFuncName = __PRETTY_FUNCTION__,
30         string moduleName = __MODULE__,
31         Args...)(Args args)
32     {
33         if (args.length == 0)
34         {
35             return;
36         }
37 
38         DateTime dt = now;
39         if ((dt.date != today) || (fl is null))
40         {
41             synchronized (_mutex)
42             {
43                 if ((dt.date != today) || (fl is null))
44                 {
45                     if (fl !is null)
46                     {
47                         fl.file.flush();
48                         fl.file.close();
49                     }
50 
51                     today = dt.date;
52                     const auto filename = buildPath(getExePath(), "log", dt.year.to!string, dt.date.toISOString() ~ ".log");
53                     fl = new FileLogger(filename, LogLevel.all, CreateFolder.yes);
54                 }
55             }
56         }
57 
58         fl.log!(line, file, funcName, prettyFuncName, moduleName)(getExeName, ": ", args);
59     }
60 
61     static void flush(const bool closeFile = false)
62     {
63         synchronized (_mutex)
64         {
65             fl.file.flush();
66 
67             if (closeFile)
68             {
69                 fl.file.close();
70                 fl = null;
71             }
72         }
73     }
74 }
75 alias logger = Logger;
76 
77 
78 /// classification file logger.
79 struct LoggerEx
80 {
81     private __gshared Date today;
82     private __gshared FileLogger[size_t] fl;
83 
84     private __gshared Mutex _mutex;
85  
86     private static this()
87     {
88         _mutex = new Mutex();
89     }
90 
91     /// write log to file.
92     static void write(string file = __FILE__, size_t line = __LINE__,
93         string funcName = __FUNCTION__,
94         string prettyFuncName = __PRETTY_FUNCTION__,
95         string moduleName = __MODULE__,
96         T = size_t,
97         Args...)(T classification, Args args)
98     {
99         if (args.length == 0)
100         {
101             return;
102         }
103 
104         const size_t _class = cast(size_t) classification;
105         DateTime dt = now;
106 
107         if ((dt.date != today) || (_class !in fl) || (fl[_class] is null))
108         {
109             synchronized (_mutex)
110             {
111                 if ((dt.date != today) || (_class !in fl) || (fl[_class] is null))
112                 {
113                     if ((_class in fl) && (fl[_class] !is null))
114                     {
115                         fl[_class].file.flush();
116                         fl[_class].file.close();
117                     }
118 
119                     today = dt.date;
120                     const auto filename = buildPath(getExePath(), "log", dt.year.to!string, dt.date.toISOString(), _class.to!string ~ ".log");
121                     fl[_class] = new FileLogger(filename, LogLevel.all, CreateFolder.yes);
122                 }
123             }
124         }
125 
126         fl[_class].log!(line, file, funcName, prettyFuncName, moduleName)(getExeName, ": ", args);
127     }
128 
129     static void flush(const bool closeFile = false)
130     {
131         synchronized (_mutex)
132         {
133             foreach (ref f; fl)
134             {
135                 f.file.flush();
136 
137                 if (closeFile)
138                 {
139                     f.file.close();
140                     f = null;
141                 }
142             }
143         }
144     }
145 }
146 alias loggerEx = LoggerEx;
147 
148 
149 void writelnEx(string file = __FILE__, size_t line = __LINE__,
150         string funcName = __FUNCTION__,
151         string prettyFuncName = __PRETTY_FUNCTION__,
152         string moduleName = __MODULE__,
153         Args...)(Args args)
154 {
155     writeln(appbase.utils.now, " ", file, ":", line, ":", funcName, ": ", args);
156 }