< Summary

Information
Class: Ice.Internal.LoggerAdminI.RemoteLoggerData
Assembly: Ice
File(s): /home/runner/work/ice/ice/csharp/src/Ice/Internal/LoggerAdminI.cs
Tag: 71_18251537082
Line coverage
100%
Covered lines: 4
Uncovered lines: 0
Coverable lines: 4
Total lines: 458
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage
100%
Covered methods: 1
Total methods: 1
Method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%

File(s)

/home/runner/work/ice/ice/csharp/src/Ice/Internal/LoggerAdminI.cs

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