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