1 /******************************************************************************* 2 3 InsertConsole 4 5 An appender for the tango logger which writes the output _above_ the 6 current cursor position, breaking the line automatically. 7 8 This appender was developed in order to allow applications using 9 ocean.io.console.AppStatus to split the output console to send logs to the 10 top streaming portion without affecting the bottom static portion. For more 11 details, please refer to the documentation in the AppStatus module. 12 13 Copyright: 14 Copyright (c) 2009-2016 dunnhumby Germany GmbH. 15 All rights reserved. 16 17 License: 18 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 19 Alternatively, this file may be distributed under the terms of the Tango 20 3-Clause BSD License (see LICENSE_BSD.txt for details). 21 22 *******************************************************************************/ 23 24 module ocean.util.log.InsertConsole; 25 26 27 import ocean.meta.types.Qualifiers; 28 import ocean.core.Verify; 29 30 import ocean.io.Terminal; 31 32 import ocean.io.Console; 33 34 import Integer = ocean.text.convert.Integer_tango; 35 36 import ocean.io.model.IConduit; 37 import ocean.util.log.Appender; 38 import ocean.util.log.Event; 39 40 import core.sys.posix.signal; 41 42 43 /******************************************************************************* 44 45 An appender for the tango logger which writes the output _above_ the 46 current cursor position, breaking the line automatically 47 48 This was copied from ocean.util.log.AppendConsole and modified 49 50 *******************************************************************************/ 51 52 public class InsertConsole: Appender 53 { 54 private Mask mask_; 55 private bool flush_; 56 private OutputStream stream_; 57 58 private char[] buffer; 59 60 /*********************************************************************** 61 62 Create with the given layout 63 64 ***********************************************************************/ 65 66 this ( Appender.Layout how = null ) 67 { 68 this(Cerr.stream, true, how); 69 } 70 71 /*********************************************************************** 72 73 Create with the given stream and layout 74 75 ***********************************************************************/ 76 77 this ( OutputStream stream, bool flush = false, Appender.Layout how = null ) 78 { 79 verify (stream !is null); 80 81 mask_ = register(name ~ stream.classinfo.name); 82 this.connectOutput(stream); 83 flush_ = flush; 84 layout(how); 85 86 this.buffer = new char[Terminal.columns]; 87 this.buffer[] = '\0'; 88 } 89 90 /*********************************************************************** 91 92 Sets the output stream to the different stream. 93 94 Params: 95 output = stream to output to. 96 97 ***********************************************************************/ 98 99 void connectOutput ( OutputStream stream ) 100 { 101 this.stream_ = stream; 102 } 103 104 /*********************************************************************** 105 106 Return the fingerprint for this class 107 108 ***********************************************************************/ 109 110 final override Mask mask ( ) 111 { 112 return mask_; 113 } 114 115 /*********************************************************************** 116 117 Return the name of this class 118 119 ***********************************************************************/ 120 121 override cstring name ( ) 122 { 123 return this.classinfo.name; 124 } 125 126 /*********************************************************************** 127 128 Append an event to the output. 129 130 ***********************************************************************/ 131 132 final override void append ( LogEvent event ) 133 { 134 // attempt to format output for non-existing terminal will cause 135 // an infinite loop 136 if (!Terminal.columns) 137 return; 138 139 if (this.buffer.length != Terminal.columns) 140 { 141 this.buffer.length = Terminal.columns; 142 buffer[] = '\0'; 143 } 144 145 ushort pos = 0; 146 147 static immutable istring Eol = "\n"; 148 149 with ( Terminal ) 150 { 151 layout.format( 152 event, 153 ( cstring content ) 154 { 155 size_t written; 156 while (pos + content.length > buffer.length) 157 { 158 buffer[pos .. $] = content[0 .. buffer.length - pos]; 159 160 written += stream_.write(CSI); 161 written += stream_.write(LINE_UP); 162 163 written += stream_.write(CSI); 164 written += stream_.write(SCROLL_UP); 165 166 written += stream_.write(CSI); 167 written += stream_.write(INSERT_LINE); 168 169 written += stream_.write(buffer); 170 171 stream_.write(Eol); 172 stream_.flush; 173 buffer[] = '\0'; 174 content = content[buffer.length - pos .. $]; 175 176 pos = 0; 177 } 178 179 if (content.length > 0) 180 { 181 buffer[pos .. pos + content.length] = content[]; 182 pos += content.length; 183 } 184 } ); 185 186 stream_.write(CSI); 187 stream_.write(LINE_UP); 188 189 stream_.write(CSI); 190 stream_.write(SCROLL_UP); 191 192 stream_.write(CSI); 193 stream_.write(INSERT_LINE); 194 195 stream_.write(buffer); 196 stream_.flush; 197 198 pos = 0; 199 buffer[] = '\0'; 200 201 stream_.write(Eol); 202 203 if (flush_) stream_.flush; 204 } 205 } 206 }