< Summary

Information
Class: Ice.Internal.LoggerAdminI
Assembly: Ice
File(s): /home/runner/work/ice/ice/csharp/src/Ice/Internal/LoggerAdminI.cs
Tag: 71_18251537082
Line coverage
77%
Covered lines: 133
Uncovered lines: 39
Coverable lines: 172
Total lines: 458
Line coverage: 77.3%
Branch coverage
75%
Covered branches: 84
Total branches: 112
Branch coverage: 75%
Method coverage
93%
Covered methods: 15
Total methods: 16
Method coverage: 93.7%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
attachRemoteLogger(...)68.75%19.251676.67%
performInitAsync()50%3.19233.33%
detachRemoteLogger(...)33.33%10.5650%
getLog(...)75%4.1481.82%
.ctor(...)100%11100%
destroy()100%44100%
log(...)85%51.594080.65%
deadRemoteLogger(...)0%2040%
getTraceLevel()100%11100%
filterLogMessages(...)100%2626100%
changeCommunicator(...)50%2.06275%
copyProperties(...)50%2.15266.67%
createSendLogCommunicator(...)16.67%7.64664.29%
removeRemoteLogger(...)100%11100%
.ctor(...)100%11100%
.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    {
 117        if (prx == null)
 18        {
 019            return; // can't send this null RemoteLogger anything!
 20        }
 21
 122        Ice.RemoteLoggerPrx remoteLogger = Ice.RemoteLoggerPrxHelper.uncheckedCast(prx.ice_twoway());
 23
 124        var filters = new Filters(messageTypes, categories);
 125        LinkedList<Ice.LogMessage> initLogMessages = null;
 26
 127        lock (_mutex)
 28        {
 129            if (_sendLogCommunicator == null)
 30            {
 131                if (_destroyed)
 32                {
 033                    throw new Ice.ObjectNotExistException();
 34                }
 35
 136                _sendLogCommunicator =
 137                    createSendLogCommunicator(current.adapter.getCommunicator(), _logger.getLocalLogger());
 38            }
 39
 140            Ice.Identity remoteLoggerId = remoteLogger.ice_getIdentity();
 41
 142            if (_remoteLoggerMap.ContainsKey(remoteLoggerId))
 43            {
 144                if (_traceLevel > 0)
 45                {
 046                    _logger.trace(_traceCategory, "rejecting `" + remoteLogger.ToString() +
 047                                 "' with RemoteLoggerAlreadyAttachedException");
 48                }
 49
 150                throw new Ice.RemoteLoggerAlreadyAttachedException();
 51            }
 52
 153            _remoteLoggerMap.Add(
 154                remoteLoggerId,
 155                new RemoteLoggerData(changeCommunicator(remoteLogger, _sendLogCommunicator), filters));
 56
 157            if (messageMax != 0)
 58            {
 159                initLogMessages = new LinkedList<Ice.LogMessage>(_queue); // copy
 60            }
 61            else
 62            {
 063                initLogMessages = new LinkedList<Ice.LogMessage>();
 64            }
 065        }
 66
 167        if (_traceLevel > 0)
 68        {
 069            _logger.trace(_traceCategory, "attached `" + remoteLogger.ToString() + "'");
 70        }
 71
 172        if (initLogMessages.Count > 0)
 73        {
 174            filterLogMessages(initLogMessages, filters.messageTypes, filters.traceCategories, messageMax);
 75        }
 76
 177        _ = performInitAsync();
 78
 79        async Task performInitAsync()
 80        {
 81            try
 82            {
 183                await remoteLogger.initAsync(_logger.getPrefix(), initLogMessages.ToArray()).ConfigureAwait(false);
 184                if (_traceLevel > 1)
 85                {
 086                    _logger.trace(
 087                        _traceCategory,
 088                        $"init on `{remoteLogger}' completed successfully");
 89                }
 190            }
 091            catch (Ice.LocalException ex)
 92            {
 093                deadRemoteLogger(remoteLogger, _logger, ex, "init");
 094            }
 095            catch (System.Exception ex)
 96            {
 97                Debug.Fail($"unexpected exception {ex}");
 098                throw;
 99            }
 1100        }
 1101    }
 102
 103    public override bool
 104    detachRemoteLogger(Ice.RemoteLoggerPrx remoteLogger, Ice.Current current)
 105    {
 1106        if (remoteLogger == null)
 107        {
 0108            return false;
 109        }
 110
 111        //
 112        // No need to convert the proxy as we only use its identity
 113        //
 1114        bool found = removeRemoteLogger(remoteLogger);
 115
 1116        if (_traceLevel > 0)
 117        {
 0118            if (found)
 119            {
 0120                _logger.trace(_traceCategory, "detached `" + remoteLogger.ToString() + "'");
 121            }
 122            else
 123            {
 0124                _logger.trace(_traceCategory, "cannot detach `" + remoteLogger.ToString() + "': not found");
 125            }
 126        }
 127
 1128        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    {
 1139        LinkedList<Ice.LogMessage> logMessages = null;
 1140        lock (_mutex)
 141        {
 1142            if (messageMax != 0)
 143            {
 1144                logMessages = new LinkedList<Ice.LogMessage>(_queue);
 145            }
 146            else
 147            {
 0148                logMessages = new LinkedList<Ice.LogMessage>();
 149            }
 0150        }
 151
 1152        prefix = _logger.getPrefix();
 153
 1154        if (logMessages.Count > 0)
 155        {
 1156            var filters = new Filters(messageTypes, categories);
 1157            filterLogMessages(logMessages, filters.messageTypes, filters.traceCategories, messageMax);
 158        }
 1159        return logMessages.ToArray();
 160    }
 161
 1162    internal LoggerAdminI(Ice.Properties props, LoggerAdminLoggerI logger)
 163    {
 1164        _maxLogCount = props.getIcePropertyAsInt("Ice.Admin.Logger.KeepLogs");
 1165        _maxTraceCount = props.getIcePropertyAsInt("Ice.Admin.Logger.KeepTraces");
 1166        _traceLevel = props.getIcePropertyAsInt("Ice.Trace.Admin.Logger");
 1167        _logger = logger;
 1168    }
 169
 170    internal void destroy()
 171    {
 1172        Ice.Communicator sendLogCommunicator = null;
 173
 1174        lock (_mutex)
 175        {
 1176            if (!_destroyed)
 177            {
 1178                _destroyed = true;
 1179                sendLogCommunicator = _sendLogCommunicator;
 1180                _sendLogCommunicator = null;
 181            }
 1182        }
 183
 184        //
 185        // Destroy outside lock to avoid deadlock when there are outstanding two-way log calls sent to
 186        // remote loggers
 187        //
 1188        sendLogCommunicator?.destroy();
 1189    }
 190
 191    internal List<Ice.RemoteLoggerPrx> log(Ice.LogMessage logMessage)
 192    {
 1193        lock (_mutex)
 194        {
 1195            List<Ice.RemoteLoggerPrx> remoteLoggers = null;
 196
 197            //
 198            // Put message in _queue
 199            //
 1200            if ((logMessage.type != Ice.LogMessageType.TraceMessage && _maxLogCount > 0) ||
 1201               (logMessage.type == Ice.LogMessageType.TraceMessage && _maxTraceCount > 0))
 202            {
 1203                _queue.AddLast(logMessage);
 204
 1205                if (logMessage.type != Ice.LogMessageType.TraceMessage)
 206                {
 207                    Debug.Assert(_maxLogCount > 0);
 1208                    if (_logCount == _maxLogCount)
 209                    {
 210                        //
 211                        // Need to remove the oldest log from the queue
 212                        //
 213                        Debug.Assert(_oldestLog != null);
 0214                        LinkedListNode<LogMessage> next = _oldestLog.Next;
 0215                        _queue.Remove(_oldestLog);
 0216                        _oldestLog = next;
 217
 0218                        while (_oldestLog != null && _oldestLog.Value.type == Ice.LogMessageType.TraceMessage)
 219                        {
 0220                            _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);
 1227                        _logCount++;
 1228                        _oldestLog ??= _queue.Last;
 229                    }
 230                }
 231                else
 232                {
 233                    Debug.Assert(_maxTraceCount > 0);
 1234                    if (_traceCount == _maxTraceCount)
 235                    {
 236                        //
 237                        // Need to remove the oldest trace from the queue
 238                        //
 239                        Debug.Assert(_oldestTrace != null);
 1240                        LinkedListNode<LogMessage> next = _oldestTrace.Next;
 1241                        _queue.Remove(_oldestTrace);
 1242                        _oldestTrace = next;
 243
 1244                        while (_oldestTrace != null && _oldestTrace.Value.type != Ice.LogMessageType.TraceMessage)
 245                        {
 0246                            _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);
 1253                        _traceCount++;
 1254                        _oldestTrace ??= _queue.Last;
 255                    }
 256                }
 257            }
 258
 259            //
 260            // Queue updated, now find which remote loggers want this message
 261            //
 1262            foreach (RemoteLoggerData p in _remoteLoggerMap.Values)
 263            {
 1264                Filters filters = p.filters;
 265
 1266                if (filters.messageTypes.Count == 0 || filters.messageTypes.Contains(logMessage.type))
 267                {
 1268                    if (logMessage.type != Ice.LogMessageType.TraceMessage || filters.traceCategories.Count == 0 ||
 1269                       filters.traceCategories.Contains(logMessage.traceCategory))
 270                    {
 1271                        remoteLoggers ??= new List<Ice.RemoteLoggerPrx>();
 1272                        remoteLoggers.Add(p.remoteLogger);
 273                    }
 274                }
 275            }
 276
 1277            return remoteLoggers;
 278        }
 1279    }
 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        //
 0287        if (removeRemoteLogger(remoteLogger))
 288        {
 0289            if (_traceLevel > 0)
 290            {
 0291                logger.trace(_traceCategory, "detached `" + remoteLogger.ToString() + "' because "
 0292                             + operation + " raised:\n" + ex.ToString());
 293            }
 294        }
 0295    }
 296
 1297    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        //
 1311        if (messageTypes.Count > 0 || traceCategories.Count > 0 || messageMax > 0)
 312        {
 1313            int count = 0;
 1314            LinkedListNode<LogMessage> p = logMessages.Last;
 1315            while (p != null)
 316            {
 1317                bool keepIt = false;
 1318                Ice.LogMessage msg = p.Value;
 1319                if (messageTypes.Count == 0 || messageTypes.Contains(msg.type))
 320                {
 1321                    if (msg.type != Ice.LogMessageType.TraceMessage || traceCategories.Count == 0 ||
 1322                       traceCategories.Contains(msg.traceCategory))
 323                    {
 1324                        keepIt = true;
 325                    }
 326                }
 327
 1328                if (keepIt)
 329                {
 1330                    ++count;
 1331                    if (messageMax > 0 && count >= messageMax)
 332                    {
 333                        // Remove all older messages
 1334                        p = p.Previous;
 1335                        while (p != null)
 336                        {
 1337                            LinkedListNode<LogMessage> previous = p.Previous;
 1338                            logMessages.Remove(p);
 1339                            p = previous;
 340                        }
 1341                        break; // while
 342                    }
 343                    else
 344                    {
 1345                        p = p.Previous;
 346                    }
 347                }
 348                else
 349                {
 1350                    LinkedListNode<LogMessage> previous = p.Previous;
 1351                    logMessages.Remove(p);
 1352                    p = previous;
 353                }
 354            }
 355        }
 356        // else, don't need any filtering
 1357    }
 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    {
 1364        if (prx == null)
 365        {
 0366            return null;
 367        }
 368
 1369        ObjectPrx result = ObjectPrxHelper.createProxy(communicator, prx.ToString());
 1370        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    {
 1375        foreach (KeyValuePair<string, string> p in from.getPropertiesForPrefix(prefix))
 376        {
 0377            to.setProperty(p.Key, p.Value);
 378        }
 1379    }
 380
 381    private static Ice.Communicator createSendLogCommunicator(Ice.Communicator communicator, Ice.Logger logger)
 382    {
 1383        var initData = new Ice.InitializationData();
 1384        initData.logger = logger;
 1385        initData.properties = new Ice.Properties();
 386
 1387        Ice.Properties mainProps = communicator.getProperties();
 388
 1389        copyProperties("Ice.Default.Locator", mainProps, initData.properties);
 1390        copyProperties("IceSSL.", mainProps, initData.properties);
 391
 1392        string[] extraProps = mainProps.getIcePropertyAsList("Ice.Admin.Logger.Properties");
 393
 1394        if (extraProps.Length > 0)
 395        {
 0396            for (int i = 0; i < extraProps.Length; ++i)
 397            {
 0398                string p = extraProps[i];
 0399                if (!p.StartsWith("--", StringComparison.Ordinal))
 400                {
 0401                    extraProps[i] = "--" + p;
 402                }
 403            }
 0404            initData.properties.parseCommandLineOptions("", extraProps);
 405        }
 1406        return Ice.Util.initialize(initData);
 407    }
 408
 409    private bool removeRemoteLogger(Ice.RemoteLoggerPrx remoteLogger)
 410    {
 1411        lock (_mutex)
 412        {
 1413            return _remoteLoggerMap.Remove(remoteLogger.ice_getIdentity());
 414        }
 1415    }
 416
 1417    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;
 1426    private readonly object _mutex = new();
 427
 428    private class Filters
 429    {
 1430        internal Filters(Ice.LogMessageType[] m, string[] c)
 431        {
 1432            messageTypes = new HashSet<Ice.LogMessageType>(m);
 1433            traceCategories = new HashSet<string>(c);
 1434        }
 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
 1452    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}