1 /++
2  + Copyright: Copyright © 2017, Christian Köstlin
3  + License: MIT
4  + Authors: Christian Koestlin
5  +/
6 
7 module androidlogger;
8 
9 public import androidlogger.packageversion;
10 
11 import std.experimental.logger;
12 
13 class AndroidLogger : FileLogger
14 {
15     import std.stdio;
16     import std.string;
17     import std.concurrency;
18     import std.process;
19     import colored;
20 
21     private string[LogLevel] logLevel2String;
22     private bool withColors;
23 
24     this(bool withColors = true, LogLevel level = LogLevel.all) @system
25     {
26         super(stdout, level);
27         this.withColors = withColors;
28         initLogLevel2String();
29     }
30 
31     static string tid2string(Tid id) @trusted
32     {
33         import std.conv : text;
34 
35         return text(id).replace("Tid(", "").replace(")", "");
36     }
37 
38     override void writeLogMsg(ref LogEntry payload) @trusted
39     {
40         with (payload)
41         {
42             // android logoutput looks lokes this:
43             // 06-06 12:14:46.355 372 18641 D audio_hw_primary: disable_audio_route: reset and update
44             // DATE  TIME         PID TID   LEVEL TAG           Message
45             auto h = timestamp.fracSecs.split!("msecs");
46             auto idx = msg.indexOf(':');
47             string tag = ""; // "%s.%d".format(file, line),
48             string text = "";
49             if (idx == -1)
50             {
51                 tag = "stdout";
52                 text = msg;
53             }
54             else
55             {
56                 tag = msg[0 .. idx];
57                 text = msg[idx + 1 .. $];
58             }
59             this.file.lockingTextWriter()
60                 .put(colorize("%02d-%02d %02d:%02d:%02d.%03d %d %s %s %s: %s\n".format(timestamp.month, // DATE
61                         timestamp.day, timestamp.hour, // TIME
62                         timestamp.minute, timestamp.second,
63                         h.msecs, std.process.thisProcessID, // PID
64                         tid2string(threadId), // TID
65                         logLevel2String[logLevel], tag, text), logLevel).toString);
66 
67         }
68     }
69 
70     private void initLogLevel2String()
71     {
72         logLevel2String[LogLevel.trace] = "T";
73         logLevel2String[LogLevel.info] = "I";
74         logLevel2String[LogLevel.warning] = "W";
75         logLevel2String[LogLevel.error] = "E";
76         logLevel2String[LogLevel.critical] = "C";
77         logLevel2String[LogLevel.fatal] = "F";
78     }
79 
80     private auto colorize(string s, LogLevel logLevel)
81     {
82         if (!withColors)
83         {
84             return s.defaultColor.onDefaultColor;
85         }
86 
87         switch (logLevel)
88         {
89         case LogLevel.trace:
90             return s.black.onDefaultColor;
91         case LogLevel.info:
92             return s.defaultColor.onDefaultColor;
93         case LogLevel.warning:
94             return s.green.onDefaultColor;
95         case LogLevel.error:
96             return s.yellow.onDefaultColor;
97         case LogLevel.critical:
98             return s.black.onRed;
99         case LogLevel.fatal:
100             return s.yellow.onRed;
101         default:
102             assert(0);
103         }
104     }
105 }