1 // 2 // Copyright (c) ZeroC, Inc. All rights reserved. 3 // 4 5 using System.Collections.Generic; 6 using System.Diagnostics; 7 using System.Linq; 8 9 namespace IceInternal 10 { 11 sealed class LoggerAdminI : Ice.LoggerAdminDisp_ 12 { 13 public override void attachRemoteLogger(Ice.RemoteLoggerPrx prx, Ice.LogMessageType[] messageTypes, string[] categories, int messageMax, Ice.Current current)14 attachRemoteLogger(Ice.RemoteLoggerPrx prx, Ice.LogMessageType[] messageTypes, string[] categories, 15 int messageMax, Ice.Current current) 16 { 17 if(prx == null) 18 { 19 return; // can't send this null RemoteLogger anything! 20 } 21 22 Ice.RemoteLoggerPrx remoteLogger = Ice.RemoteLoggerPrxHelper.uncheckedCast(prx.ice_twoway()); 23 24 Filters filters = new Filters(messageTypes, categories); 25 LinkedList<Ice.LogMessage> initLogMessages = null; 26 27 lock(this) 28 { 29 if(_sendLogCommunicator == null) 30 { 31 if(_destroyed) 32 { 33 throw new Ice.ObjectNotExistException(); 34 } 35 36 _sendLogCommunicator = 37 createSendLogCommunicator(current.adapter.getCommunicator(), _logger.getLocalLogger()); 38 } 39 40 Ice.Identity remoteLoggerId = remoteLogger.ice_getIdentity(); 41 42 if(_remoteLoggerMap.ContainsKey(remoteLoggerId)) 43 { 44 if(_traceLevel > 0) 45 { 46 _logger.trace(_traceCategory, "rejecting `" + remoteLogger.ToString() + 47 "' with RemoteLoggerAlreadyAttachedException"); 48 } 49 50 throw new Ice.RemoteLoggerAlreadyAttachedException(); 51 } 52 53 _remoteLoggerMap.Add(remoteLoggerId, 54 new RemoteLoggerData(changeCommunicator(remoteLogger, _sendLogCommunicator), filters)); 55 56 if(messageMax != 0) 57 { 58 initLogMessages = new LinkedList<Ice.LogMessage>(_queue); // copy 59 } 60 else 61 { 62 initLogMessages = new LinkedList<Ice.LogMessage>(); 63 } 64 } 65 66 if(_traceLevel > 0) 67 { 68 _logger.trace(_traceCategory, "attached `" + remoteLogger.ToString() + "'"); 69 } 70 71 if(initLogMessages.Count > 0) 72 { 73 filterLogMessages(initLogMessages, filters.messageTypes, filters.traceCategories, messageMax); 74 } 75 76 try 77 { 78 remoteLogger.initAsync(_logger.getPrefix(), initLogMessages.ToArray()).ContinueWith( 79 (t) => 80 { 81 try 82 { 83 t.Wait(); 84 if(_traceLevel > 1) 85 { 86 _logger.trace(_traceCategory,"init on `" + remoteLogger.ToString() 87 + "' completed successfully"); 88 } 89 } 90 catch(System.AggregateException ae) 91 { 92 Debug.Assert(ae.InnerException is Ice.LocalException); 93 deadRemoteLogger(remoteLogger, _logger, (Ice.LocalException)ae.InnerException, "init"); 94 } 95 }); 96 } 97 catch(Ice.LocalException ex) 98 { 99 deadRemoteLogger(remoteLogger, _logger, ex, "init"); 100 throw; 101 } 102 } 103 104 public override bool detachRemoteLogger(Ice.RemoteLoggerPrx remoteLogger, Ice.Current current)105 detachRemoteLogger(Ice.RemoteLoggerPrx remoteLogger, Ice.Current current) 106 { 107 if(remoteLogger == null) 108 { 109 return false; 110 } 111 112 // 113 // No need to convert the proxy as we only use its identity 114 // 115 bool found = removeRemoteLogger(remoteLogger); 116 117 if(_traceLevel > 0) 118 { 119 if(found) 120 { 121 _logger.trace(_traceCategory, "detached `" + remoteLogger.ToString() + "'"); 122 } 123 else 124 { 125 _logger.trace(_traceCategory, "cannot detach `" + remoteLogger.ToString() + "': not found"); 126 } 127 } 128 129 return found; 130 } 131 132 public override Ice.LogMessage[] getLog(Ice.LogMessageType[] messageTypes, string[] categories, int messageMax, out string prefix, Ice.Current current)133 getLog(Ice.LogMessageType[] messageTypes, string[] categories, int messageMax, out string prefix, 134 Ice.Current current) 135 { 136 LinkedList<Ice.LogMessage> logMessages = null; 137 lock(this) 138 { 139 if(messageMax != 0) 140 { 141 logMessages = new LinkedList<Ice.LogMessage>(_queue); 142 } 143 else 144 { 145 logMessages = new LinkedList<Ice.LogMessage>(); 146 } 147 } 148 149 prefix = _logger.getPrefix(); 150 151 if(logMessages.Count > 0) 152 { 153 Filters filters = new Filters(messageTypes, categories); 154 filterLogMessages(logMessages, filters.messageTypes, filters.traceCategories, messageMax); 155 } 156 return logMessages.ToArray(); 157 } 158 LoggerAdminI(Ice.Properties props, LoggerAdminLoggerI logger)159 internal LoggerAdminI(Ice.Properties props, LoggerAdminLoggerI logger) 160 { 161 _maxLogCount = props.getPropertyAsIntWithDefault("Ice.Admin.Logger.KeepLogs", 100); 162 _maxTraceCount = props.getPropertyAsIntWithDefault("Ice.Admin.Logger.KeepTraces", 100); 163 _traceLevel = props.getPropertyAsInt("Ice.Trace.Admin.Logger"); 164 _logger = logger; 165 } 166 destroy()167 internal void destroy() 168 { 169 Ice.Communicator sendLogCommunicator = null; 170 171 lock(this) 172 { 173 if(!_destroyed) 174 { 175 _destroyed = true; 176 sendLogCommunicator = _sendLogCommunicator; 177 _sendLogCommunicator = null; 178 } 179 } 180 181 // 182 // Destroy outside lock to avoid deadlock when there are outstanding two-way log calls sent to 183 // remote loggers 184 // 185 if(sendLogCommunicator != null) 186 { 187 sendLogCommunicator.destroy(); 188 } 189 } 190 log(Ice.LogMessage logMessage)191 internal List<Ice.RemoteLoggerPrx> log(Ice.LogMessage logMessage) 192 { 193 lock(this) 194 { 195 List<Ice.RemoteLoggerPrx> remoteLoggers = null; 196 197 // 198 // Put message in _queue 199 // 200 if((logMessage.type != Ice.LogMessageType.TraceMessage && _maxLogCount > 0) || 201 (logMessage.type == Ice.LogMessageType.TraceMessage && _maxTraceCount > 0)) 202 { 203 _queue.AddLast(logMessage); 204 205 if(logMessage.type != Ice.LogMessageType.TraceMessage) 206 { 207 Debug.Assert(_maxLogCount > 0); 208 if(_logCount == _maxLogCount) 209 { 210 // 211 // Need to remove the oldest log from the queue 212 // 213 Debug.Assert(_oldestLog != null); 214 var next = _oldestLog.Next; 215 _queue.Remove(_oldestLog); 216 _oldestLog = next; 217 218 while(_oldestLog != null && _oldestLog.Value.type == Ice.LogMessageType.TraceMessage) 219 { 220 _oldestLog = _oldestLog.Next; 221 } 222 Debug.Assert(_oldestLog != null); // remember: we just added a Log at the end 223 } 224 else 225 { 226 Debug.Assert(_logCount < _maxLogCount); 227 _logCount++; 228 if(_oldestLog == null) 229 { 230 _oldestLog = _queue.Last; 231 } 232 } 233 } 234 else 235 { 236 Debug.Assert(_maxTraceCount > 0); 237 if(_traceCount == _maxTraceCount) 238 { 239 // 240 // Need to remove the oldest trace from the queue 241 // 242 Debug.Assert(_oldestTrace != null); 243 var next = _oldestTrace.Next; 244 _queue.Remove(_oldestTrace); 245 _oldestTrace = next; 246 247 while(_oldestTrace != null && _oldestTrace.Value.type != Ice.LogMessageType.TraceMessage) 248 { 249 _oldestTrace = _oldestTrace.Next; 250 } 251 Debug.Assert(_oldestTrace != null); // remember: we just added a Log at the end 252 } 253 else 254 { 255 Debug.Assert(_traceCount < _maxTraceCount); 256 _traceCount++; 257 if(_oldestTrace == null) 258 { 259 _oldestTrace = _queue.Last; 260 } 261 } 262 } 263 } 264 265 // 266 // Queue updated, now find which remote loggers want this message 267 // 268 foreach(RemoteLoggerData p in _remoteLoggerMap.Values) 269 { 270 Filters filters = p.filters; 271 272 if(filters.messageTypes.Count == 0 || filters.messageTypes.Contains(logMessage.type)) 273 { 274 if(logMessage.type != Ice.LogMessageType.TraceMessage || filters.traceCategories.Count == 0 || 275 filters.traceCategories.Contains(logMessage.traceCategory)) 276 { 277 if(remoteLoggers == null) 278 { 279 remoteLoggers = new List<Ice.RemoteLoggerPrx>(); 280 } 281 remoteLoggers.Add(p.remoteLogger); 282 } 283 } 284 } 285 286 return remoteLoggers; 287 } 288 } 289 deadRemoteLogger(Ice.RemoteLoggerPrx remoteLogger, Ice.Logger logger, Ice.LocalException ex, string operation)290 internal void deadRemoteLogger(Ice.RemoteLoggerPrx remoteLogger, Ice.Logger logger, Ice.LocalException ex, 291 string operation) 292 { 293 // 294 // No need to convert remoteLogger as we only use its identity 295 // 296 if(removeRemoteLogger(remoteLogger)) 297 { 298 if(_traceLevel > 0) 299 { 300 logger.trace(_traceCategory, "detached `" + remoteLogger.ToString() + "' because " 301 + operation + " raised:\n" + ex.ToString()); 302 } 303 } 304 } 305 getTraceLevel()306 internal int getTraceLevel() 307 { 308 return _traceLevel; 309 } 310 removeRemoteLogger(Ice.RemoteLoggerPrx remoteLogger)311 private bool removeRemoteLogger(Ice.RemoteLoggerPrx remoteLogger) 312 { 313 lock(this) 314 { 315 return _remoteLoggerMap.Remove(remoteLogger.ice_getIdentity()); 316 } 317 } 318 filterLogMessages(LinkedList<Ice.LogMessage> logMessages, HashSet<Ice.LogMessageType> messageTypes, HashSet<string> traceCategories, int messageMax)319 private static void filterLogMessages(LinkedList<Ice.LogMessage> logMessages, 320 HashSet<Ice.LogMessageType> messageTypes, 321 HashSet<string> traceCategories, int messageMax) 322 { 323 Debug.Assert(logMessages.Count > 0 && messageMax != 0); 324 325 // 326 // Filter only if one of the 3 filters is set; messageMax < 0 means "give me all" 327 // that match the other filters, if any. 328 // 329 if(messageTypes.Count > 0 || traceCategories.Count > 0 || messageMax > 0) 330 { 331 int count = 0; 332 var p = logMessages.Last; 333 while(p != null) 334 { 335 bool keepIt = false; 336 Ice.LogMessage msg = p.Value; 337 if(messageTypes.Count == 0 || messageTypes.Contains(msg.type)) 338 { 339 if(msg.type != Ice.LogMessageType.TraceMessage || traceCategories.Count == 0 || 340 traceCategories.Contains(msg.traceCategory)) 341 { 342 keepIt = true; 343 } 344 } 345 346 if(keepIt) 347 { 348 ++count; 349 if(messageMax > 0 && count >= messageMax) 350 { 351 // Remove all older messages 352 p = p.Previous; 353 while(p != null) 354 { 355 var previous = p.Previous; 356 logMessages.Remove(p); 357 p = previous; 358 } 359 break; // while 360 } 361 else 362 { 363 p = p.Previous; 364 } 365 } 366 else 367 { 368 var previous = p.Previous; 369 logMessages.Remove(p); 370 p = previous; 371 } 372 } 373 } 374 // else, don't need any filtering 375 } 376 377 // 378 // Change this proxy's communicator, while keeping its invocation timeout 379 // changeCommunicator(Ice.RemoteLoggerPrx prx, Ice.Communicator communicator)380 private static Ice.RemoteLoggerPrx changeCommunicator(Ice.RemoteLoggerPrx prx, Ice.Communicator communicator) 381 { 382 if(prx == null) 383 { 384 return null; 385 } 386 387 Ice.ObjectPrx result = communicator.stringToProxy(prx.ToString()); 388 return Ice.RemoteLoggerPrxHelper.uncheckedCast(result.ice_invocationTimeout(prx.ice_getInvocationTimeout())); 389 } 390 copyProperties(string prefix, Ice.Properties from, Ice.Properties to)391 private static void copyProperties(string prefix, Ice.Properties from, Ice.Properties to) 392 { 393 foreach(var p in from.getPropertiesForPrefix(prefix)) 394 { 395 to.setProperty(p.Key, p.Value); 396 } 397 } 398 createSendLogCommunicator(Ice.Communicator communicator, Ice.Logger logger)399 private static Ice.Communicator createSendLogCommunicator(Ice.Communicator communicator, Ice.Logger logger) 400 { 401 Ice.InitializationData initData = new Ice.InitializationData(); 402 initData.logger = logger; 403 initData.properties = Ice.Util.createProperties(); 404 405 Ice.Properties mainProps = communicator.getProperties(); 406 407 copyProperties("Ice.Default.Locator", mainProps, initData.properties); 408 copyProperties("Ice.Plugin.IceSSL", mainProps, initData.properties); 409 copyProperties("IceSSL.", mainProps, initData.properties); 410 411 string[] extraProps = mainProps.getPropertyAsList("Ice.Admin.Logger.Properties"); 412 413 if(extraProps.Length > 0) 414 { 415 for(int i = 0; i < extraProps.Length; ++i) 416 { 417 string p = extraProps[i]; 418 if(!p.StartsWith("--")) 419 { 420 extraProps[i] = "--" + p; 421 } 422 } 423 initData.properties.parseCommandLineOptions("", extraProps); 424 } 425 return Ice.Util.initialize(initData); 426 } 427 428 private readonly LinkedList<Ice.LogMessage> _queue = new LinkedList<Ice.LogMessage>(); 429 private int _logCount = 0; // non-trace messages 430 private readonly int _maxLogCount; 431 private int _traceCount = 0; 432 private readonly int _maxTraceCount; 433 private readonly int _traceLevel; 434 435 private LinkedListNode<Ice.LogMessage> _oldestTrace = null; 436 private LinkedListNode<Ice.LogMessage> _oldestLog = null; 437 438 private class Filters 439 { Filters(Ice.LogMessageType[] m, string[] c)440 internal Filters(Ice.LogMessageType[] m, string[] c) 441 { 442 messageTypes = new HashSet<Ice.LogMessageType>(m); 443 traceCategories = new HashSet<string>(c); 444 } 445 446 internal readonly HashSet<Ice.LogMessageType> messageTypes; 447 internal readonly HashSet<string> traceCategories; 448 } 449 450 private class RemoteLoggerData 451 { RemoteLoggerData(Ice.RemoteLoggerPrx prx, Filters f)452 internal RemoteLoggerData(Ice.RemoteLoggerPrx prx, Filters f) 453 { 454 remoteLogger = prx; 455 filters = f; 456 } 457 458 internal readonly Ice.RemoteLoggerPrx remoteLogger; 459 internal readonly Filters filters; 460 } 461 462 private readonly Dictionary<Ice.Identity, RemoteLoggerData> _remoteLoggerMap 463 = new Dictionary<Ice.Identity, RemoteLoggerData>(); 464 465 private readonly LoggerAdminLoggerI _logger; 466 467 private Ice.Communicator _sendLogCommunicator = null; 468 private bool _destroyed = false; 469 static private readonly string _traceCategory = "Admin.Logger"; 470 } 471 472 } 473