< Summary

Information
Class: Ice.Internal.LoggerAdminLoggerI.Job
Assembly: Ice
File(s): /_/csharp/src/Ice/Internal/LoggerAdminLoggerI.cs
Tag: 91_21789722663
Line coverage
100%
Covered lines: 4
Uncovered lines: 0
Coverable lines: 4
Total lines: 221
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)

/_/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{
 18    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;
 23    private readonly Queue<Job> _jobQueue = new Queue<Job>();
 24    private const string _traceCategory = "Admin.Logger";
 25    private readonly object _mutex = new();
 26
 27    public void print(string message)
 28    {
 29        _localLogger.print(message);
 30        if (!_detached)
 31        {
 32            var logMessage = new LogMessage(LogMessageType.PrintMessage, now(), "", message);
 33            log(logMessage);
 34        }
 35    }
 36
 37    public void trace(string category, string message)
 38    {
 39        _localLogger.trace(category, message);
 40        if (!_detached)
 41        {
 42            var logMessage = new LogMessage(LogMessageType.TraceMessage, now(), category, message);
 43            log(logMessage);
 44        }
 45    }
 46
 47    public void warning(string message)
 48    {
 49        _localLogger.warning(message);
 50        if (!_detached)
 51        {
 52            var logMessage = new LogMessage(LogMessageType.WarningMessage, now(), "", message);
 53            log(logMessage);
 54        }
 55    }
 56
 57    public void error(string message)
 58    {
 59        _localLogger.error(message);
 60        if (!_detached)
 61        {
 62            var logMessage = new LogMessage(LogMessageType.ErrorMessage, now(), "", message);
 63            log(logMessage);
 64        }
 65    }
 66
 67    public string getPrefix() => _localLogger.getPrefix();
 68
 69    public Logger cloneWithPrefix(string prefix) => _localLogger.cloneWithPrefix(prefix);
 70
 71    public Ice.Object getFacet() => _loggerAdmin;
 72
 73    public void detach()
 74    {
 75        Thread thread = null;
 76        lock (_mutex)
 77        {
 78            if (_sendLogThread != null)
 79            {
 80                thread = _sendLogThread;
 81                _sendLogThread = null;
 82                _detached = true;
 83                Monitor.PulseAll(_mutex);
 84            }
 85        }
 86
 87        thread?.Join();
 88
 89        _loggerAdmin.destroy();
 90    }
 91
 92    public void Dispose()
 93    {
 94        detach();
 95        _localLogger.Dispose();
 96    }
 97
 98    internal LoggerAdminLoggerI(Ice.Properties props, Ice.Logger localLogger)
 99    {
 100        if (localLogger is LoggerAdminLoggerI wrapper)
 101        {
 102            _localLogger = wrapper.getLocalLogger();
 103        }
 104        else
 105        {
 106            _localLogger = localLogger;
 107        }
 108
 109        _loggerAdmin = new LoggerAdminI(props, this);
 110    }
 111
 112    internal Ice.Logger getLocalLogger() => _localLogger;
 113
 114    internal void log(Ice.LogMessage logMessage)
 115    {
 116        List<Ice.RemoteLoggerPrx> remoteLoggers = _loggerAdmin.log(logMessage);
 117
 118        if (remoteLoggers != null)
 119        {
 120            Debug.Assert(remoteLoggers.Count > 0);
 121
 122            lock (_mutex)
 123            {
 124                if (_sendLogThread == null)
 125                {
 126                    _sendLogThread = new Thread(new ThreadStart(run));
 127                    _sendLogThread.Name = "Ice.SendLogThread";
 128                    _sendLogThread.IsBackground = true;
 129                    _sendLogThread.Start();
 130                }
 131
 132                _jobQueue.Enqueue(new Job(remoteLoggers, logMessage));
 133                Monitor.PulseAll(_mutex);
 134            }
 135        }
 136    }
 137
 138    private static long now()
 139    {
 140        TimeSpan t = DateTime.UtcNow - _unixEpoch;
 141        return Convert.ToInt64(t.TotalMilliseconds * 1000);
 142    }
 143
 144    private void run()
 145    {
 146        if (_loggerAdmin.getTraceLevel() > 1)
 147        {
 148            _localLogger.trace(_traceCategory, "send log thread started");
 149        }
 150
 151        while (true)
 152        {
 153            Job job = null;
 154            lock (_mutex)
 155            {
 156                while (!_detached && _jobQueue.Count == 0)
 157                {
 158                    Monitor.Wait(_mutex);
 159                }
 160
 161                if (_detached)
 162                {
 163                    break;
 164                }
 165
 166                Debug.Assert(_jobQueue.Count > 0);
 167                job = _jobQueue.Dequeue();
 168            }
 169
 170            foreach (RemoteLoggerPrx p in job.remoteLoggers)
 171            {
 172                if (_loggerAdmin.getTraceLevel() > 1)
 173                {
 174                    _localLogger.trace(_traceCategory, $"sending log message to '{p}'");
 175                }
 176
 177                //
 178                // p is a proxy associated with the _sendLogCommunicator
 179                //
 180                _ = performLogAsync(p, job.logMessage);
 181            }
 182        }
 183
 184        if (_loggerAdmin.getTraceLevel() > 1)
 185        {
 186            _localLogger.trace(_traceCategory, "send log thread completed");
 187        }
 188
 189        async Task performLogAsync(RemoteLoggerPrx logger, LogMessage logMessage)
 190        {
 191            try
 192            {
 193                await logger.logAsync(logMessage).ConfigureAwait(false);
 194                if (_loggerAdmin.getTraceLevel() > 1)
 195                {
 196                    _localLogger.trace(_traceCategory, $"log on '{logger}' completed successfully");
 197                }
 198            }
 199            catch (Ice.CommunicatorDestroyedException)
 200            {
 201                // expected if there are outstanding calls during communicator destruction
 202            }
 203            catch (Ice.LocalException ex)
 204            {
 205                _loggerAdmin.deadRemoteLogger(logger, _localLogger, ex, "log");
 206            }
 207        }
 208    }
 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}