Skip to content

Commit b23bbbf

Browse files
brettsamahmelsayed
authored andcommitted
adding console output for ILogger
1 parent 958972c commit b23bbbf

File tree

6 files changed

+155
-11
lines changed

6 files changed

+155
-11
lines changed

src/Azure.Functions.Cli/Azure.Functions.Cli.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,9 @@
739739
<Compile Include="Common\Utilities.cs" />
740740
<Compile Include="ConsoleApp.cs" />
741741
<Compile Include="Context.cs" />
742+
<Compile Include="Diagnostics\CliLoggerFactoryBuilder.cs" />
743+
<Compile Include="Diagnostics\ColoredConsoleLogger.cs" />
744+
<Compile Include="Diagnostics\ColoredConsoleLoggerProvider.cs" />
742745
<Compile Include="Diagnostics\ConsoleTraceWriter.cs" />
743746
<Compile Include="Extensions\DictionaryExtensions.cs" />
744747
<Compile Include="Extensions\FunctionMetadataExtensions.cs" />

src/Azure.Functions.Cli/Common/SelfHostWebHostSettingsFactory.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,30 @@
11
using System;
22
using System.Diagnostics;
33
using System.IO;
4-
using Microsoft.Azure.WebJobs.Script.WebHost;
54
using Azure.Functions.Cli.Diagnostics;
6-
using Azure.Functions.Cli.Helpers;
5+
using Colors.Net;
6+
using Microsoft.Azure.WebJobs.Script.WebHost;
77

88
namespace Azure.Functions.Cli.Common
99
{
1010
internal static class SelfHostWebHostSettingsFactory
1111
{
1212
public static WebHostSettings Create(TraceLevel consoleTraceLevel, string scriptPath)
1313
{
14+
// We want to prevent any Console writers added by the core WebJobs SDK
15+
// from writing to console, so we set our output to the original console TextWriter
16+
// and replace it with a Null TextWriter
17+
ColoredConsole.Out = new ColoredConsoleWriter(Console.Out);
18+
Console.SetOut(TextWriter.Null);
19+
1420
return new WebHostSettings
1521
{
1622
IsSelfHost = true,
1723
ScriptPath = scriptPath,
1824
LogPath = Path.Combine(Path.GetTempPath(), @"LogFiles\Application\Functions"),
1925
SecretsPath = Path.Combine(Path.GetTempPath(), "secrets", "functions", "secrets"),
2026
TraceWriter = new ConsoleTraceWriter(consoleTraceLevel),
27+
LoggerFactoryBuilder = new CliLoggerFactoryBuilder(),
2128
IsAuthDisabled = true
2229
};
2330
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using Microsoft.Azure.WebJobs.Script;
2+
using Microsoft.Azure.WebJobs.Script.Config;
3+
using Microsoft.Extensions.Logging;
4+
5+
namespace Azure.Functions.Cli.Diagnostics
6+
{
7+
internal class CliLoggerFactoryBuilder : DefaultLoggerFactoryBuilder
8+
{
9+
public override void AddLoggerProviders(ILoggerFactory factory, ScriptHostConfiguration scriptConfig, ScriptSettingsManager settingsManager)
10+
{
11+
base.AddLoggerProviders(factory, scriptConfig, settingsManager);
12+
13+
factory.AddProvider(new ColoredConsoleLoggerProvider(scriptConfig.LogFilter.Filter));
14+
}
15+
}
16+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.Linq;
5+
using Microsoft.Azure.WebJobs.Host;
6+
using Microsoft.Azure.WebJobs.Script;
7+
using Microsoft.Extensions.Logging;
8+
9+
namespace Azure.Functions.Cli.Diagnostics
10+
{
11+
public class ColoredConsoleLogger : ILogger
12+
{
13+
private readonly Func<string, LogLevel, bool> _filter;
14+
private readonly string _category;
15+
private readonly TraceWriter _consoleTraceWriter;
16+
17+
public ColoredConsoleLogger(string category, Func<string, LogLevel, bool> filter)
18+
{
19+
_category = category;
20+
_filter = filter;
21+
22+
// Use a ConsoleTraceWriter to handle all formatting
23+
_consoleTraceWriter = new ConsoleTraceWriter(TraceLevel.Verbose);
24+
}
25+
26+
public bool IsEnabled(LogLevel logLevel)
27+
{
28+
if (_filter == null)
29+
{
30+
return true;
31+
}
32+
33+
return _filter(_category, logLevel);
34+
}
35+
36+
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
37+
{
38+
if (!IsEnabled(logLevel))
39+
{
40+
return;
41+
}
42+
43+
// TraceWriter traces are forwarded to ILoggers. Ignore them to prevent duplicate logging.
44+
if (IsFromTraceWriter(state as IEnumerable<KeyValuePair<string, object>>))
45+
{
46+
return;
47+
}
48+
49+
string formattedMessage = formatter(state, exception);
50+
51+
TraceEvent trace = new TraceEvent(GetTraceLevel(logLevel), formattedMessage, exception: exception);
52+
_consoleTraceWriter.Trace(trace);
53+
}
54+
55+
private static TraceLevel GetTraceLevel(LogLevel level)
56+
{
57+
switch (level)
58+
{
59+
case LogLevel.Error:
60+
return TraceLevel.Error;
61+
case LogLevel.Warning:
62+
return TraceLevel.Warning;
63+
case LogLevel.Information:
64+
return TraceLevel.Info;
65+
case LogLevel.Debug:
66+
case LogLevel.Trace:
67+
return TraceLevel.Verbose;
68+
default:
69+
return TraceLevel.Off;
70+
}
71+
}
72+
73+
public IDisposable BeginScope<TState>(TState state)
74+
{
75+
return null;
76+
}
77+
78+
private static bool IsFromTraceWriter(IEnumerable<KeyValuePair<string, object>> properties)
79+
{
80+
if (properties == null)
81+
{
82+
return false;
83+
}
84+
else
85+
{
86+
return properties.Any(kvp => string.Equals(kvp.Key, ScriptConstants.TracePropertyIsUserTraceKey, StringComparison.OrdinalIgnoreCase));
87+
}
88+
}
89+
}
90+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
using Microsoft.Azure.WebJobs.Logging;
3+
using Microsoft.Extensions.Logging;
4+
using Microsoft.Extensions.Logging.Abstractions;
5+
6+
namespace Azure.Functions.Cli.Diagnostics
7+
{
8+
public class ColoredConsoleLoggerProvider : ILoggerProvider
9+
{
10+
private readonly Func<string, LogLevel, bool> _filter;
11+
12+
public ColoredConsoleLoggerProvider(Func<string, LogLevel, bool> filter)
13+
{
14+
_filter = filter;
15+
}
16+
17+
public ILogger CreateLogger(string categoryName)
18+
{
19+
// Restrict any console logging from the ILogger to only the "Function" category, which are logs
20+
// coming directly from a function. This removes duplicate host logging.
21+
if (categoryName == LogCategories.Function)
22+
{
23+
return new ColoredConsoleLogger(categoryName, _filter);
24+
}
25+
else
26+
{
27+
return NullLogger.Instance;
28+
}
29+
}
30+
31+
public void Dispose()
32+
{
33+
}
34+
}
35+
}

src/Azure.Functions.Cli/Diagnostics/ConsoleTraceWriter.cs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Diagnostics;
3-
using System.IO;
44
using Colors.Net;
5-
using Colors.Net.StringColorExtensions;
65
using Microsoft.Azure.WebJobs.Host;
7-
using static Azure.Functions.Cli.Common.OutputTheme;
86
using Microsoft.Azure.WebJobs.Script;
9-
using System.Collections.Generic;
7+
using static Azure.Functions.Cli.Common.OutputTheme;
108

119
namespace Azure.Functions.Cli.Diagnostics
1210
{
1311
public class ConsoleTraceWriter : TraceWriter
1412
{
1513
public ConsoleTraceWriter(TraceLevel level) : base(level)
1614
{
17-
// We want to prevent any Console writers added by the core WebJobs SDK
18-
// from writing to console, so we set our output to the original console TextWriter
19-
// and replace it with a Null TextWriter
20-
ColoredConsole.Out = new ColoredConsoleWriter(Console.Out);
21-
Console.SetOut(TextWriter.Null);
2215
}
2316

2417
public override void Trace(TraceEvent traceEvent)

0 commit comments

Comments
 (0)