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 }