< Summary

Information
Class: Ice.Internal.LoggerAdminLoggerI
Assembly: Ice
File(s): /_/csharp/src/Ice/Internal/LoggerAdminLoggerI.cs
Tag: 91_21789722663
Line coverage
88%
Covered lines: 81
Uncovered lines: 11
Coverable lines: 92
Total lines: 221
Line coverage: 88%
Branch coverage
85%
Covered branches: 29
Total branches: 34
Branch coverage: 85.2%
Method coverage
94%
Covered methods: 16
Total methods: 17
Method coverage: 94.1%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
.ctor(...)50%2.01287.5%
print(...)100%22100%
trace(...)100%22100%
warning(...)100%22100%
error(...)100%22100%
getPrefix()100%11100%
cloneWithPrefix(...)100%210%
getFacet()100%11100%
detach()100%44100%
Dispose()100%11100%
getLocalLogger()100%11100%
log(...)100%44100%
now()100%11100%
run()78.57%15.081482.35%
performLogAsync()50%2.86240%
.ctor(...)100%11100%

File(s)

/_/csharp/src/Ice/Internal/LoggerAdminLoggerI.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3using System.Diagnostics;
 4
 5namespace Ice.Internal;
 6
 7internal interface LoggerAdminLogger : Logger
 8{
 9    Ice.Object getFacet();
 10
 11    // Once detach is called, the logger only logs to the local logger.
 12    void detach();
 13}
 14
 15// Decorates a logger.
 16internal sealed class LoggerAdminLoggerI : LoggerAdminLogger
 17{
 118    private static readonly DateTime _unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
 19    private readonly Logger _localLogger;
 20    private readonly LoggerAdminI _loggerAdmin;
 21    private Thread _sendLogThread;
 22    private volatile bool _detached;
 123    private readonly Queue<Job> _jobQueue = new Queue<Job>();
 24    private const string _traceCategory = "Admin.Logger";
 125    private readonly object _mutex = new();
 26
 27    public void print(string message)
 28    {
 129        _localLogger.print(message);
 130        if (!_detached)
 31        {
 132            var logMessage = new LogMessage(LogMessageType.PrintMessage, now(), "", message);
 133            log(logMessage);
 34        }
 135    }
 36
 37    public void trace(string category, string message)
 38    {
 139        _localLogger.trace(category, message);
 140        if (!_detached)
 41        {
 142            var logMessage = new LogMessage(LogMessageType.TraceMessage, now(), category, message);
 143            log(logMessage);
 44        }
 145    }
 46
 47    public void warning(string message)
 48    {
 149        _localLogger.warning(message);
 150        if (!_detached)
 51        {
 152            var logMessage = new LogMessage(LogMessageType.WarningMessage, now(), "", message);
 153            log(logMessage);
 54        }
 155    }
 56
 57    public void error(string message)
 58    {
 159        _localLogger.error(message);
 160        if (!_detached)
 61        {
 162            var logMessage = new LogMessage(LogMessageType.ErrorMessage, now(), "", message);
 163            log(logMessage);
 64        }
 165    }
 66
 167    public string getPrefix() => _localLogger.getPrefix();
 68
 069    public Logger cloneWithPrefix(string prefix) => _localLogger.cloneWithPrefix(prefix);
 70
 171    public Ice.Object getFacet() => _loggerAdmin;
 72
 73    public void detach()
 74    {
 175        Thread thread = null;
 176        lock (_mutex)
 77        {
 178            if (_sendLogThread != null)
 79            {
 180                thread = _sendLogThread;
 181                _sendLogThread = null;
 182                _detached = true;
 183                Monitor.PulseAll(_mutex);
 84            }
 185        }
 86
 187        thread?.Join();
 88
 189        _loggerAdmin.destroy();
 190    }
 91
 92    public void Dispose()
 93    {
 194        detach();
 195        _localLogger.Dispose();
 196    }
 97
 198    internal LoggerAdminLoggerI(Ice.Properties props, Ice.Logger localLogger)
 99    {
 1100        if (localLogger is LoggerAdminLoggerI wrapper)
 101        {
 0102            _localLogger = wrapper.getLocalLogger();
 103        }
 104        else
 105        {
 1106            _localLogger = localLogger;
 107        }
 108
 1109        _loggerAdmin = new LoggerAdminI(props, this);
 1110    }
 111
 1112    internal Ice.Logger getLocalLogger() => _localLogger;
 113
 114    internal void log(Ice.LogMessage logMessage)
 115    {
 1116        List<Ice.RemoteLoggerPrx> remoteLoggers = _loggerAdmin.log(logMessage);
 117
 1118        if (remoteLoggers != null)
 119        {
 120            Debug.Assert(remoteLoggers.Count > 0);
 121
 1122            lock (_mutex)
 123            {
 1124                if (_sendLogThread == null)
 125                {
 1126                    _sendLogThread = new Thread(new ThreadStart(run));
 1127                    _sendLogThread.Name = "Ice.SendLogThread";
 1128                    _sendLogThread.IsBackground = true;
 1129                    _sendLogThread.Start();
 130                }
 131
 1132                _jobQueue.Enqueue(new Job(remoteLoggers, logMessage));
 1133                Monitor.PulseAll(_mutex);
 1134            }
 135        }
 1136    }
 137
 138    private static long now()
 139    {
 1140        TimeSpan t = DateTime.UtcNow - _unixEpoch;
 1141        return Convert.ToInt64(t.TotalMilliseconds * 1000);
 142    }
 143
 144    private void run()
 145    {
 1146        if (_loggerAdmin.getTraceLevel() > 1)
 147        {
 0148            _localLogger.trace(_traceCategory, "send log thread started");
 149        }
 150
 151        while (true)
 152        {
 1153            Job job = null;
 1154            lock (_mutex)
 155            {
 1156                while (!_detached && _jobQueue.Count == 0)
 157                {
 1158                    Monitor.Wait(_mutex);
 159                }
 160
 1161                if (_detached)
 162                {
 1163                    break;
 164                }
 165
 166                Debug.Assert(_jobQueue.Count > 0);
 1167                job = _jobQueue.Dequeue();
 1168            }
 169
 1170            foreach (RemoteLoggerPrx p in job.remoteLoggers)
 171            {
 1172                if (_loggerAdmin.getTraceLevel() > 1)
 173                {
 0174                    _localLogger.trace(_traceCategory, $"sending log message to '{p}'");
 175                }
 176
 177                //
 178                // p is a proxy associated with the _sendLogCommunicator
 179                //
 1180                _ = performLogAsync(p, job.logMessage);
 181            }
 182        }
 183
 1184        if (_loggerAdmin.getTraceLevel() > 1)
 185        {
 0186            _localLogger.trace(_traceCategory, "send log thread completed");
 187        }
 188
 189        async Task performLogAsync(RemoteLoggerPrx logger, LogMessage logMessage)
 190        {
 191            try
 192            {
 1193                await logger.logAsync(logMessage).ConfigureAwait(false);
 1194                if (_loggerAdmin.getTraceLevel() > 1)
 195                {
 0196                    _localLogger.trace(_traceCategory, $"log on '{logger}' completed successfully");
 197                }
 1198            }
 0199            catch (Ice.CommunicatorDestroyedException)
 200            {
 201                // expected if there are outstanding calls during communicator destruction
 0202            }
 0203            catch (Ice.LocalException ex)
 204            {
 0205                _loggerAdmin.deadRemoteLogger(logger, _localLogger, ex, "log");
 0206            }
 1207        }
 1208    }
 209
 210    private class Job
 211    {
 1212        internal Job(List<Ice.RemoteLoggerPrx> r, Ice.LogMessage l)
 213        {
 1214            remoteLoggers = r;
 1215            logMessage = l;
 1216        }
 217
 218        internal readonly List<Ice.RemoteLoggerPrx> remoteLoggers;
 219        internal readonly Ice.LogMessage logMessage;
 220    }
 221}