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