1 module puppeteer.logging.basic_logger;
2 
3 import puppeteer.logging.logging_exception;
4 
5 import std.concurrency;
6 import std.stdio;
7 import std.conv;
8 
9 package shared struct BasicLogger
10 {
11     private static int next_id = 0;
12     private int id;
13 
14     @property
15     private string loggerTidName()
16     {
17         enum nameBase = "puppeteer.logging.basic_logger";
18 
19         return nameBase ~ to!string(id);
20     }
21 
22     @property
23     private Tid loggerTid()
24     {
25         return locate(loggerTidName);
26     }
27 
28     this(string logFilename)
29     {
30         id = next_id++;
31 
32         Tid loggerTid = spawn(&loggingLoop, logFilename);
33         register(loggerTidName, loggerTid);
34 
35         receive(
36             (LoopInitializedMessage msg)
37             {
38                 if(!msg.success)
39                     throw new LoggingException(msg.errorMsg);
40             }
41         );
42     }
43 
44     void log(string message)
45     {
46         loggerTid.send(message);
47     }
48 
49     ~this()
50     {
51         if(loggerTid != Tid.init)
52             loggerTid.send(EndLoggingMessage());
53     }
54 }
55 
56 private void loggingLoop(string logFilename)
57 {
58     import std.stdio;
59     import std.exception : ErrnoException;
60 
61     File loggingFile;
62 
63     try
64     {
65         loggingFile = File(logFilename, "a");
66     }
67     catch(ErrnoException e)
68     {
69         ownerTid.send(LoopInitializedMessage(false, "Could not open logging file " ~ logFilename ~ "."));
70         return;
71     }
72 
73     ownerTid.send(LoopInitializedMessage(true));
74 
75     bool shouldContinue = true;
76 
77     while(shouldContinue)
78     {
79         receive(
80             (string msg)
81             {
82                 loggingFile.writeln(msg);
83                 loggingFile.flush();
84             },
85             (EndLoggingMessage msg)
86             {
87                 shouldContinue = false;
88             }
89         );
90     }
91 }
92 
93 private struct LoopInitializedMessage
94 {
95     bool success;
96     string errorMsg;
97 
98     this(bool success, string errorMsg = "")
99     body
100     {
101         this.success = success;
102     }
103 }
104 
105 private struct EndLoggingMessage
106 {
107 
108 }