1 /** 2 * Copyright: Copyright Jason White, 2016 3 * License: MIT 4 * Authors: Jason White 5 * 6 * Description: 7 * General logging of events. 8 */ 9 module button.log.file; 10 11 import core.time : TickDuration; 12 13 import button.log; 14 import button.task; 15 import button.state; 16 17 import io.file.stream; 18 import io.text; 19 20 final class FileLogger : Logger 21 { 22 import button.textcolor : TextColor; 23 24 private 25 { 26 // File stream to log to 27 File file; 28 29 // True if output should be verbose. 30 bool verbose; 31 32 TextColor color; 33 } 34 35 private final class FileTaskLogger : TaskLogger 36 { 37 private 38 { 39 import std.range : appender, Appender; 40 41 Task task; 42 Appender!(ubyte[]) _output; 43 } 44 45 this(Task task) 46 { 47 this.task = task; 48 _output = appender!(ubyte[]); 49 } 50 51 void output(in ubyte[] chunk) 52 { 53 _output.put(chunk); 54 } 55 56 private void printOutput() 57 { 58 file.write(_output.data); 59 60 // Ensure there is always a line separator after the output 61 if (_output.data.length > 0 && _output.data[$-1] != '\n') 62 file.print("⏎\n"); 63 } 64 65 private void printTail(TickDuration duration) 66 { 67 import core.time : Duration; 68 if (verbose) 69 file.println(color.status, " ➥ Time taken: ", color.reset, 70 cast(Duration)duration); 71 } 72 73 void succeeded(TickDuration duration) 74 { 75 synchronized (this.outer) 76 { 77 file.println(color.status, " > ", color.reset, 78 task.toPrettyString(verbose)); 79 80 printOutput(); 81 printTail(duration); 82 } 83 } 84 85 void failed(TickDuration duration, Exception e) 86 { 87 import std.string : wrap; 88 89 synchronized (this.outer) 90 { 91 file.println(color.status, " > ", color.error, 92 task.toPrettyString(verbose), color.reset); 93 94 printOutput(); 95 printTail(duration); 96 97 enum indent = " "; 98 99 file.print(color.status, " ➥ ", color.error, "Error: ", 100 color.reset, wrap(e.msg, 80, "", indent, 4)); 101 } 102 } 103 } 104 105 this(File file, bool verbose) 106 { 107 this.file = file; 108 this.verbose = verbose; 109 this.color = TextColor(true); 110 } 111 112 void buildStarted() 113 { 114 } 115 116 void buildEnded(bool success, TickDuration duration) 117 { 118 } 119 120 TaskLogger taskStarted(Index!Task index, Task task, bool dryRun) 121 { 122 return new FileTaskLogger(task); 123 } 124 }