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