private static void WriteDiagnosticsToConsole()

in src/Azure.IIoT.OpcUa.Publisher/src/Services/RuntimeStateReporter.cs [521:721]


        private static void WriteDiagnosticsToConsole(
            IEnumerable<(string, WriterGroupDiagnosticModel)> diagnostics, bool includeResourceInfo)
        {
            var builder = new StringBuilder();
            foreach (var (writerGroupId, info) in diagnostics)
            {
                builder = Append(builder, writerGroupId, info, includeResourceInfo);
            }

            if (builder.Length > 0)
            {
                Console.Out.WriteLine(builder.ToString());
            }

            static StringBuilder Append(StringBuilder builder, string writerGroupId,
                WriterGroupDiagnosticModel info, bool includeResourceInfo)
            {
                var s = info.IngestionDuration.TotalSeconds == 0 ? 1 : info.IngestionDuration.TotalSeconds;
                var min = info.IngestionDuration.TotalMinutes == 0 ? 1 : info.IngestionDuration.TotalMinutes;

                var eventsPerSec = info.IngressEvents / s;
                var eventNotificationsPerSec = info.IngressEventNotifications / s;

                var sentMessagesPerSecFormatted = info.OutgressIoTMessageCount > 0 ? $"({info.SentMessagesPerSec:n2}/s)"
                    : string.Empty;
                var keepAliveChangesPerSecFormatted = info.IngressKeepAliveNotifications > 0 ?
                        $"(All time ~{info.IngressKeepAliveNotifications / min:n2}/min)"
                    : string.Empty;

                var dataChangesPerSecFormatted =
                    Format(info.IngressDataChanges, info.IngressDataChangesInLastMinute, s);
                var valueChangesPerSecFormatted =
                    Format(info.IngressValueChanges, info.IngressValueChangesInLastMinute, s);
                var eventsPerSecFormatted =
                    Format(info.IngressEvents, info.IngressEventsInLastMinute, s);
                var eventNotificationsPerSecFormatted =
                    Format(info.IngressEventNotifications, info.IngressEventNotificationsInLastMinute, s);
                var heartbeatsPerSecFormatted =
                    Format(info.IngressHeartbeats, info.IngressHeartbeatsInLastMinute, s);
                var cyclicReadsPerSecFormatted =
                    Format(info.IngressCyclicReads, info.IngressCyclicReadsInLastMinute, s);
                var sampledValuesPerSecFormatted =
                    Format(info.IngressSampledValues, info.IngressSampledValuesInLastMinute, s);
                var modelChangesPerSecFormatted =
                    Format(info.IngressModelChanges, info.IngressModelChangesInLastMinute, s);
                var serverQueueOverflowsPerSecFormatted =
                    Format(info.ServerQueueOverflows, info.ServerQueueOverflowsInLastMinute, s);

                static string Format(long changes, long lastMinute, double s)
                {
                    var dataChangesPerSecLastMin = lastMinute / Math.Min(s, 60d);
                    return changes > 0 ?
                        $"(All time ~{changes / s:n2}/s; {lastMinute:n0} in last 60s ~{dataChangesPerSecLastMin:n2}/s)"
                            : string.Empty;
                }

                var chunkUsageFormatted = Math.Round(info.EncoderAvgIoTChunkUsage, 2) > 0 ?
                    $"(Avg Chunk (4 KB) usage {info.EncoderAvgIoTChunkUsage:n2}; {info.EstimatedIoTChunksPerDay:n1}/day estimated)"
                        : string.Empty;
                var connectivityState = info.NumberOfConnectedEndpoints > 0 ? (info.NumberOfDisconnectedEndpoints > 0 ?
                    "(Partially Connected)" : "(Connected)") : "(Disconnected)";

                var sb = builder.AppendLine()
                    .Append("  DIAGNOSTICS INFORMATION for          : ")
                        .Append(info.WriterGroupName ?? Constants.DefaultWriterGroupName)
                        .Append(" (")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0:0}", writerGroupId)
                        .AppendLine(")")
                    .Append("  # OPC Publisher Version (Runtime)    : ")
                        .AppendLine(info.PublisherVersion)
                        ;
                if (includeResourceInfo)
                {
                    sb = sb
                    .Append("  # Cpu (%limit/%req/%used)            : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:p2}", info.CpuLimitUtilization)
                        .Append(" | ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0:p2}", info.CpuRequestUtilization)
                        .Append(" (")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0:p2}", info.CpuUsedPercentage)
                        .AppendLine(")")
                    .Append("  # Memory (%limit/%used/total used)   : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:p2}", info.MemoryLimitUtilization)
                        .Append(" | ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0:p2}", info.MemoryUsedPercentage)
                        .Append(" (")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0:n0}", info.MemoryUsedInBytes / 1000d)
                        .AppendLine(" KB)")
                        ;
                }
                return sb
                    .Append("  # Ingest duration (dd:hh:mm:ss)/Time : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:dd\\:hh\\:mm\\:ss}", info.IngestionDuration)
                        .Append(" | ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:O}", info.Timestamp)
                        .AppendLine()
                    .Append("  # Number of writers in group         : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:0}", info.NumberOfWriters)
                        .AppendLine()
                    .Append("  # Good/Total number of items         : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.MonitoredOpcNodesSucceededCount).Append(" | ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0:n0}", info.MonitoredOpcNodesCount)
                        .AppendLine()
                    .Append("  # Bad/Late number of items           : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.MonitoredOpcNodesFailedCount).Append(" | ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0:n0}", info.MonitoredOpcNodesLateCount)
                        .AppendLine()
                    .Append("  # Heartbeats/Condition items active  : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.ActiveHeartbeatCount).Append(" | ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0:n0}", info.ActiveConditionCount)
                        .AppendLine()
                    .Append("  # Endpoints connected/disconnected   : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:0}", info.NumberOfConnectedEndpoints).Append(" | ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0:0}", info.NumberOfDisconnectedEndpoints).Append(' ')
                        .AppendLine(connectivityState)
                    .Append("  # Connections created/retries        : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:0}", info.ConnectionCount).Append(" | ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0:0}", info.ConnectionRetries)
                        .AppendLine()
                    .Append("  # Queued/Minimum request totals      : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:0.##}", info.TotalPublishRequests).Append(" | ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0:0.##}", info.TotalMinPublishRequests)
                        .AppendLine()
                    .Append("  # Good/Bad Publish request totals    : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:0.##}", info.TotalGoodPublishRequests).Append(" | ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0:0.##}", info.TotalBadPublishRequests)
                        .AppendLine()
                    .Append("  # Ingress value changes              : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.IngressValueChanges).Append(' ')
                        .AppendLine(valueChangesPerSecFormatted)
                    .Append("  # Ingress sampled values             : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.IngressSampledValues).Append(' ')
                        .AppendLine(sampledValuesPerSecFormatted)
                    .Append("  # Ingress events                     : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.IngressEvents).Append(' ')
                        .AppendLine(eventsPerSecFormatted)
                    .Append("  # Server queue overflows             : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.ServerQueueOverflows).Append(' ')
                        .AppendLine(serverQueueOverflowsPerSecFormatted)
                    .Append("  # Received Data Change Notifications : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.IngressDataChanges).Append(' ')
                        .AppendLine(dataChangesPerSecFormatted)
                    .Append("  # Received Event Notifications       : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.IngressEventNotifications).Append(' ')
                        .AppendLine(eventNotificationsPerSecFormatted)
                    .Append("  # Received Keep Alive Notifications  : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.IngressKeepAliveNotifications).Append(' ')
                        .AppendLine(keepAliveChangesPerSecFormatted)
                    .Append("  # Received Cyclic read Notifications : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.IngressCyclicReads).Append(' ')
                        .AppendLine(cyclicReadsPerSecFormatted)
                    .Append("  # Generated Heartbeat Notifications  : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.IngressHeartbeats).Append(' ')
                        .AppendLine(heartbeatsPerSecFormatted)
                    .Append("  # Generated Model Changes            : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.IngressModelChanges).Append(' ')
                        .AppendLine(modelChangesPerSecFormatted)
                    .Append("  # Publish queue partitions/active    : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.TotalPublishQueuePartitions).Append(" | ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0:n0}", info.ActivePublishQueuePartitions)
                        .AppendLine()
                    .Append("  # Notifications buffered/dropped     : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.IngressBatchBlockBufferSize).Append(" | ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0:n0}", info.IngressNotificationsDropped)
                        .AppendLine()
                    .Append("  # Encoder input buffer size          : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.EncodingBlockInputSize)
                        .AppendLine()
                    .Append("  # Encoder Notif. processed/dropped   : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.EncoderNotificationsProcessed).Append(" | ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0:n0}", info.EncoderNotificationsDropped)
                        .AppendLine()
                    .Append("  # Encoder Network Messages produced  : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.EncoderIoTMessagesProcessed)
                        .AppendLine()
                    .Append("  # Encoder avg Notifications/Message  : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.EncoderAvgNotificationsMessage)
                        .AppendLine()
                    .Append("  # Encoder worst Message split ratio  : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:0.##}", info.EncoderMaxMessageSplitRatio)
                        .AppendLine()
                    .Append("  # Encoder avg Message body size      : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:0.##}", info.EncoderAvgIoTMessageBodySize).Append(' ')
                        .AppendLine(chunkUsageFormatted)
                    .Append("  # Encoder output buffer size         : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.EncodingBlockOutputSize)
                        .AppendLine()
                    .Append("  # Egress Messages queued/dropped     : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.OutgressInputBufferCount).Append(" | ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0:n0}", info.OutgressInputBufferDropped)
                        .AppendLine()
                    .Append("  # Egress Message send failures       : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.OutgressIoTMessageFailedCount)
                        .AppendLine()
                    .Append("  # Egress Messages successfully sent  : ")
                        .AppendFormat(CultureInfo.CurrentCulture, "{0,14:n0}", info.OutgressIoTMessageCount)
                        .Append(' ')
                        .AppendLine(sentMessagesPerSecFormatted)
                    ;
            }
        }