1 // 2 // Copyright (c) ZeroC, Inc. All rights reserved. 3 // 4 5 using System; 6 using System.Collections.Generic; 7 using System.Diagnostics; 8 using System.Threading; 9 10 namespace IceInternal 11 { 12 13 interface LoggerAdminLogger : Ice.Logger 14 { getFacet()15 Ice.Object getFacet(); destroy()16 void destroy(); 17 } 18 19 sealed class LoggerAdminLoggerI : LoggerAdminLogger 20 { print(string message)21 public void print(string message) 22 { 23 Ice.LogMessage logMessage = new Ice.LogMessage(Ice.LogMessageType.PrintMessage, now(), "", message); 24 _localLogger.print(message); 25 log(logMessage); 26 } 27 trace(string category, string message)28 public void trace(string category, string message) 29 { 30 Ice.LogMessage logMessage = new Ice.LogMessage(Ice.LogMessageType.TraceMessage, now(), category, message); 31 _localLogger.trace(category, message); 32 log(logMessage); 33 } 34 warning(string message)35 public void warning(string message) 36 { 37 Ice.LogMessage logMessage = new Ice.LogMessage(Ice.LogMessageType.WarningMessage, now(), "", message); 38 _localLogger.warning(message); 39 log(logMessage); 40 } 41 error(string message)42 public void error(string message) 43 { 44 Ice.LogMessage logMessage = new Ice.LogMessage(Ice.LogMessageType.ErrorMessage, now(), "", message); 45 _localLogger.error(message); 46 log(logMessage); 47 } 48 getPrefix()49 public string getPrefix() 50 { 51 return _localLogger.getPrefix(); 52 } 53 cloneWithPrefix(string prefix)54 public Ice.Logger cloneWithPrefix(string prefix) 55 { 56 return _localLogger.cloneWithPrefix(prefix); 57 } 58 getFacet()59 public Ice.Object getFacet() 60 { 61 return _loggerAdmin; 62 } 63 destroy()64 public void destroy() 65 { 66 Thread thread = null; 67 lock(this) 68 { 69 if(_sendLogThread != null) 70 { 71 thread = _sendLogThread; 72 _sendLogThread = null; 73 _destroyed = true; 74 Monitor.PulseAll(this); 75 } 76 } 77 78 if(thread != null) 79 { 80 thread.Join(); 81 } 82 83 _loggerAdmin.destroy(); 84 } 85 LoggerAdminLoggerI(Ice.Properties props, Ice.Logger localLogger)86 internal LoggerAdminLoggerI(Ice.Properties props, Ice.Logger localLogger) 87 { 88 LoggerAdminLoggerI wrapper = localLogger as LoggerAdminLoggerI; 89 90 if(wrapper != null) 91 { 92 _localLogger = wrapper.getLocalLogger(); 93 } 94 else 95 { 96 _localLogger = localLogger; 97 } 98 99 _loggerAdmin = new LoggerAdminI(props, this); 100 } 101 getLocalLogger()102 internal Ice.Logger getLocalLogger() 103 { 104 return _localLogger; 105 } 106 log(Ice.LogMessage logMessage)107 internal void log(Ice.LogMessage logMessage) 108 { 109 List<Ice.RemoteLoggerPrx> remoteLoggers = _loggerAdmin.log(logMessage); 110 111 if(remoteLoggers != null) 112 { 113 Debug.Assert(remoteLoggers.Count > 0); 114 115 lock(this) 116 { 117 if(_sendLogThread == null) 118 { 119 _sendLogThread = new Thread(new ThreadStart(run)); 120 _sendLogThread.Name = "Ice.SendLogThread"; 121 _sendLogThread.IsBackground = true; 122 _sendLogThread.Start(); 123 } 124 125 _jobQueue.Enqueue(new Job(remoteLoggers, logMessage)); 126 Monitor.PulseAll(this); 127 } 128 } 129 } 130 run()131 private void run() 132 { 133 if(_loggerAdmin.getTraceLevel() > 1) 134 { 135 _localLogger.trace(_traceCategory, "send log thread started"); 136 } 137 138 for(;;) 139 { 140 Job job = null; 141 lock(this) 142 { 143 while(!_destroyed && _jobQueue.Count == 0) 144 { 145 Monitor.Wait(this); 146 } 147 148 if(_destroyed) 149 { 150 break; // for(;;) 151 } 152 153 Debug.Assert(_jobQueue.Count > 0); 154 job = _jobQueue.Dequeue(); 155 } 156 157 foreach(var p in job.remoteLoggers) 158 { 159 if(_loggerAdmin.getTraceLevel() > 1) 160 { 161 _localLogger.trace(_traceCategory, "sending log message to `" + p.ToString() + "'"); 162 } 163 164 try 165 { 166 // 167 // p is a proxy associated with the _sendLogCommunicator 168 // 169 p.logAsync(job.logMessage).ContinueWith( 170 (t) => 171 { 172 try 173 { 174 t.Wait(); 175 if(_loggerAdmin.getTraceLevel() > 1) 176 { 177 _localLogger.trace(_traceCategory, "log on `" + p.ToString() 178 + "' completed successfully"); 179 } 180 } 181 catch(AggregateException ae) 182 { 183 if(ae.InnerException is Ice.CommunicatorDestroyedException) 184 { 185 // expected if there are outstanding calls during communicator destruction 186 } 187 if(ae.InnerException is Ice.LocalException) 188 { 189 _loggerAdmin.deadRemoteLogger(p, _localLogger, 190 (Ice.LocalException)ae.InnerException, "log"); 191 } 192 } 193 }); 194 } 195 catch(Ice.LocalException ex) 196 { 197 _loggerAdmin.deadRemoteLogger(p, _localLogger, ex, "log"); 198 } 199 } 200 } 201 202 if(_loggerAdmin.getTraceLevel() > 1) 203 { 204 _localLogger.trace(_traceCategory, "send log thread completed"); 205 } 206 } 207 now()208 static private long now() 209 { 210 TimeSpan t = DateTime.UtcNow - _unixEpoch; 211 return Convert.ToInt64(t.TotalMilliseconds * 1000); 212 } 213 214 private class Job 215 { Job(List<Ice.RemoteLoggerPrx> r, Ice.LogMessage l)216 internal Job(List<Ice.RemoteLoggerPrx> r, Ice.LogMessage l) 217 { 218 remoteLoggers = r; 219 logMessage = l; 220 } 221 222 internal readonly List<Ice.RemoteLoggerPrx> remoteLoggers; 223 internal readonly Ice.LogMessage logMessage; 224 } 225 226 private readonly Ice.Logger _localLogger; 227 private readonly LoggerAdminI _loggerAdmin; 228 private bool _destroyed = false; 229 private Thread _sendLogThread; 230 private readonly Queue<Job> _jobQueue = new Queue<Job>(); 231 232 static private readonly DateTime _unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 233 static private readonly string _traceCategory = "Admin.Logger"; 234 } 235 236 } 237