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