// Copyright Keysight Technologies 2012-2019
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at http://mozilla.org/MPL/2.0/.
using System;
using System.Collections.Generic;
using OpenTap.Diagnostic;
namespace OpenTap
{
///
/// A class that prints trace messages to the console.
///
public class ConsoleTraceListener : TraceListener
{
///
/// Set logs startup time, this will affect timestamp of all log messages.
///
///
public static void SetStartupTime(DateTime time){
globalTimer = time.Ticks;
}
private static long globalTimer = DateTime.Now.Ticks;
///
/// Show verbose/debug level log messages.
///
public bool IsVerbose { get; set; }
///
/// Hide debug and information level log messages.
///
public bool IsQuiet { get; set; }
///
/// Color messages according to their level.
///
public bool IsColor { get; set; }
private bool isAnsiColorCodes = false;
private void EnableAnsiColorCodes()
{
if (OperatingSystem.Current == OperatingSystem.Windows)
{
try
{
if (Environment.GetEnvironmentVariable("OPENTAP_ANSI_COLORS") != null)
{
isAnsiColorCodes = true;
// This is a "isolated" process that has its stdoout redirected to the parent process.
// The parent process already successfully enabled ansi color codes. No need to do anything else here.
return;
}
isAnsiColorCodes = AnsiColorCodeFix.TryEnableForWin10();
if (isAnsiColorCodes)
Environment.SetEnvironmentVariable("OPENTAP_ANSI_COLORS", "1");
}
catch (Exception ex)
{
InternalTraceEvent("Console", LogEventType.Debug, 0, $"Error while enabling ANSI colors: {ex.Message}", 0);
}
}
else
{
isAnsiColorCodes = true;
}
}
///
/// Waits for the messages to be written to the console.
///
public override void Flush()
{
base.Flush();
Console.Out.Flush();
}
///
/// Creates an instance of the ConsoleTraceListener that can be used to output log messages in consoles.
///
///
///
///
public ConsoleTraceListener(bool isVerbose, bool isQuiet, bool isColor)
{
this.IsVerbose = isVerbose;
this.IsQuiet = isQuiet;
this.IsColor = isColor;
if (isColor)
EnableAnsiColorCodes();
}
internal static ConsoleColor GetColorForTraceLevel(LogEventType eventType)
{
switch (eventType)
{
case LogEventType.Error:
return ConsoleColor.Red;
case LogEventType.Warning:
return ConsoleColor.Yellow;
case LogEventType.Debug:
return ConsoleColor.DarkGray;
default:
return ConsoleColor.Gray;
}
}
internal static string GetAnsiCodeColorForTraceLevel(LogEventType eventType)
{
const string AnsiRed = "\x1B[31m";
const string AnsiYellow = "\x1B[33m";
const string AnsiLightBlue = "\x1B[36m";
const string AnsiReset = "\x1B[0m";
switch (eventType)
{
case LogEventType.Error:
return AnsiRed;
case LogEventType.Warning:
return AnsiYellow;
case LogEventType.Debug:
return AnsiLightBlue;
default:
return AnsiReset;
}
}
private void InternalTraceEvent(string source, LogEventType eventType, int id, string message, long timestamp)
{
if (eventType == LogEventType.Debug && !IsVerbose)
{
return;
}
if (eventType == LogEventType.Information && IsQuiet)
return;
string formattedLine = message;
if (IsVerbose)
{
var time = new TimeSpan(timestamp - globalTimer);
if (IsColor)
formattedLine = String.Format("{2:hh\\:mm\\:ss\\.fff} : {0,-11} : {1}", source, message, time);
else
formattedLine = String.Format("{3:hh\\:mm\\:ss\\.fff} : {0,-13} : {1,-11} : {2}", source, eventType, message, time);
}
if (IsColor)
{
if (isAnsiColorCodes)
{
string colorCode = GetAnsiCodeColorForTraceLevel(eventType);
formattedLine = colorCode + formattedLine + GetAnsiCodeColorForTraceLevel(LogEventType.Information);
}
else
{
ConsoleColor color = GetColorForTraceLevel(eventType);
if (color != currentColor)
{
currentColor = color;
Console.ForegroundColor = color;
}
}
}
if (eventType == LogEventType.Error)
Console.Error.WriteLine(formattedLine);
else
Console.WriteLine(formattedLine);
}
ConsoleColor currentColor = ConsoleColor.Gray;
///
/// Prints all log messages to the console.
///
///
public override void TraceEvents(IEnumerable events)
{
try
{
foreach (var evt in events)
InternalTraceEvent(evt.Source, (LogEventType)evt.EventType, 0, evt.Message, evt.Timestamp);
}
finally
{
if (currentColor != ConsoleColor.Gray)
{
currentColor = ConsoleColor.Gray;
Console.ForegroundColor = currentColor;
}
}
}
}
}