├── .gitignore ├── CodeCoverage.runsettings ├── LICENSE ├── Serilog.Sinks.AzureWebJobsTraceWriter.sln ├── appveyor.yml ├── readme.md ├── src └── Serilog.Sinks.AzureWebJobsTraceWriter │ ├── Properties │ └── AssemblyInfo.cs │ ├── Serilog.Sinks.AzureWebJobsTraceWriter.csproj │ ├── Serilog.Sinks.AzureWebJobsTraceWriter.nuspec │ ├── Sinks │ └── TraceWriter │ │ └── TraceWriterSink.cs │ ├── TraceWriterLoggerConfigurationExtensions.cs │ ├── app.config │ └── packages.config ├── test.ps1 └── tests └── Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests ├── Helpers ├── InMemoryTraceWriter.cs └── LogEventHelper.cs ├── Properties └── AssemblyInfo.cs ├── Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests.csproj ├── TraceWriterLoggerConfigurationExtensionsTests.cs ├── TraceWriterSinkTests.cs ├── app.config └── packages.config /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore hidden app settings and connection string files 2 | AppSettingsHidden.config 3 | ConnectionStringsHidden.config 4 | *.js.map 5 | 6 | ## Ignore Visual Studio temporary files, build results, and 7 | ## files generated by popular Visual Studio add-ons. 8 | 9 | # User-specific files 10 | *.suo 11 | *.user 12 | *.userosscache 13 | *.sln.docstates 14 | *.DotSettings 15 | 16 | # User-specific files (MonoDevelop/Xamarin Studio) 17 | *.userprefs 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | build/ 27 | bld/ 28 | [Bb]in/ 29 | [Oo]bj/ 30 | 31 | # Visual Studio 2015 cache/options directory 32 | .vs/ 33 | 34 | # MSTest test Results 35 | [Tt]est[Rr]esult*/ 36 | [Bb]uild[Ll]og.* 37 | 38 | # NUNIT 39 | *.VisualState.xml 40 | TestResult.xml 41 | 42 | # Build Results of an ATL Project 43 | [Dd]ebugPS/ 44 | [Rr]eleasePS/ 45 | dlldata.c 46 | 47 | # DNX 48 | project.lock.json 49 | artifacts/ 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opensdf 84 | *.sdf 85 | *.cachefile 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | ## TODO: Comment the next line if you want to checkin your 143 | ## web deploy settings but do note that will include unencrypted 144 | ## passwords 145 | #*.pubxml 146 | 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | 158 | # Windows Azure Build Output 159 | csx/ 160 | *.build.csdef 161 | 162 | # Windows Store app package directory 163 | AppPackages/ 164 | 165 | # Visual Studio cache files 166 | # files ending in .cache can be ignored 167 | *.[Cc]ache 168 | # but keep track of directories ending in .cache 169 | !*.[Cc]ache/ 170 | 171 | # Others 172 | ClientBin/ 173 | [Ss]tyle[Cc]op.* 174 | ~$* 175 | *~ 176 | *.dbmdl 177 | *.dbproj.schemaview 178 | *.pfx 179 | *.publishsettings 180 | node_modules/ 181 | orleans.codegen.cs 182 | 183 | # RIA/Silverlight projects 184 | Generated_Code/ 185 | 186 | # Backup & report files from converting an old project file 187 | # to a newer Visual Studio version. Backup files are not needed, 188 | # because we have git ;-) 189 | _UpgradeReport_Files/ 190 | Backup*/ 191 | UpgradeLog*.XML 192 | UpgradeLog*.htm 193 | 194 | # SQL Server files 195 | *.mdf 196 | *.ldf 197 | 198 | # Business Intelligence projects 199 | *.rdl.data 200 | *.bim.layout 201 | *.bim_*.settings 202 | 203 | # Microsoft Fakes 204 | FakesAssemblies/ 205 | 206 | # Node.js Tools for Visual Studio 207 | .ntvs_analysis.dat 208 | 209 | # Visual Studio 6 build log 210 | *.plg 211 | 212 | # Visual Studio 6 workspace options file 213 | *.opt 214 | 215 | # LightSwitch generated files 216 | GeneratedArtifacts/ 217 | _Pvt_Extensions/ 218 | ModelManifest.xml 219 | StarRez.Azure/StarRez.Azure.WebService/StarRez.Azure.WebService.csproj.DotSettings 220 | StarRez.Azure/StarRez.Azure.Website/wwwroot/js/deploy.js 221 | StarRez.Azure/StarRez.Azure.Website/wwwroot/js/deploy.js.map 222 | StarRez.Azure/StarRez.Azure.Website/wwwroot/js/deployments.js 223 | StarRez.Azure/StarRez.Azure.Website/wwwroot/js/deployments.js.map 224 | StarRez.Azure/.idea/ 225 | *.pubxml 226 | *.iml 227 | StarRez.Azure/StarRez.Azure.Website/Properties/PublishProfiles/ 228 | .idea/ 229 | StarRez.Azure/StarRez.Azure.Website/wwwroot/js/common.js 230 | StarRez.Azure/StarRez.Azure.Website/wwwroot/js/common.js.map 231 | StarRez.Azure/StarRez.Azure.Website/wwwroot/js/database.js 232 | StarRez.Azure/StarRez.Azure.Website/wwwroot/js/database.js.map 233 | StarRez.Azure/StarRez.Azure.ConsoleTest/ 234 | StarRez.Azure/StarRez.Azure.Website/Scripts/iisreset.js* 235 | *.lnk 236 | -------------------------------------------------------------------------------- /CodeCoverage.runsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | .*UnitTests.* 12 | 13 | 14 | True 15 | True 16 | True 17 | False 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 StarRez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Serilog.Sinks.AzureWebJobsTraceWriter.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26403.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{58F1E5DA-B51B-49FD-8BC6-010DED377357}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{C20A8CEA-E2DC-4045-B628-68159108B19A}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Serilog.Sinks.AzureWebJobsTraceWriter", "src\Serilog.Sinks.AzureWebJobsTraceWriter\Serilog.Sinks.AzureWebJobsTraceWriter.csproj", "{B67A68AD-36D3-47AB-9846-A21ECEADA700}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests", "tests\Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests\Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests.csproj", "{B9938905-C77E-43D6-9591-22178DFF6C02}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {B67A68AD-36D3-47AB-9846-A21ECEADA700}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {B67A68AD-36D3-47AB-9846-A21ECEADA700}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {B67A68AD-36D3-47AB-9846-A21ECEADA700}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {B67A68AD-36D3-47AB-9846-A21ECEADA700}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {B9938905-C77E-43D6-9591-22178DFF6C02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {B9938905-C77E-43D6-9591-22178DFF6C02}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {B9938905-C77E-43D6-9591-22178DFF6C02}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {B9938905-C77E-43D6-9591-22178DFF6C02}.Release|Any CPU.Build.0 = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | GlobalSection(NestedProjects) = preSolution 33 | {B67A68AD-36D3-47AB-9846-A21ECEADA700} = {58F1E5DA-B51B-49FD-8BC6-010DED377357} 34 | {B9938905-C77E-43D6-9591-22178DFF6C02} = {C20A8CEA-E2DC-4045-B628-68159108B19A} 35 | EndGlobalSection 36 | EndGlobal 37 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | skip_tags: true 3 | configuration: Release 4 | assembly_info: 5 | patch: true 6 | file: '**\AssemblyInfo.*' 7 | assembly_version: '{version}' 8 | assembly_file_version: '{version}' 9 | assembly_informational_version: '{version}' 10 | environment: 11 | COVERALLS_REPO_TOKEN: 12 | secure: LsohuXRLZ7rYIUlBx/sKRWggp6qzHWh2wge+DNrDJPnPoeQnNrKprYOBex6rpQ4f 13 | before_build: 14 | - nuget restore ".\Serilog.Sinks.AzureWebJobsTraceWriter.sln" 15 | build: 16 | project: .\Serilog.Sinks.AzureWebJobsTraceWriter.sln 17 | verbosity: minimal 18 | after_build: 19 | - nuget pack ".\src\Serilog.Sinks.AzureWebJobsTraceWriter\Serilog.Sinks.AzureWebJobsTraceWriter.nuspec" -Version %appveyor_build_version% 20 | - ps: Get-ChildItem .\*.nupkg | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } 21 | test_script: 22 | - ps: .\test.ps1 -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Serilog Azure WebJobs/Functions TraceWriter Sink 2 | 3 | [![NuGet Version](https://img.shields.io/nuget/v/Serilog.Sinks.AzureWebJobsTraceWriter.svg?style=flat)](https://www.nuget.org/packages/Serilog.Sinks.AzureWebJobsTraceWriter/) 4 | [![AppVeyor](https://img.shields.io/appveyor/ci/ScottHolden/serilog-sinks-azurewebjobstracewriter.svg)](https://ci.appveyor.com/project/ScottHolden/serilog-sinks-azurewebjobstracewriter) 5 | [![Coverage Status](https://coveralls.io/repos/github/StarRez/Serilog.Sinks.AzureWebJobsTraceWriter/badge.svg?branch=master)](https://coveralls.io/github/StarRez/Serilog.Sinks.AzureWebJobsTraceWriter?branch=master) 6 | 7 | A Serilog sink that writes events to Azure WebJob Host's TraceWriter. This is the logging mechanism used by both Azure WebJob's, and Azure Functions (which is built on top of the WebJob Host). 8 | 9 | ### Getting started 10 | 11 | Install the [Serilog.Sinks.AzureWebJobsTraceWriter](https://nuget.org/packages/Serilog.Sinks.AzureWebJobsTraceWriter/) package from NuGet. 12 | 13 | Within your logger configuration, you can now include a TraceWriter as a sink: 14 | 15 | ```csharp 16 | using Serilog.Sinks.AzureWebJobsTraceWriter; 17 | 18 | ILogger log = new LoggerConfiguration() 19 | .WriteTo.TraceWriter(traceWriter) 20 | .CreateLogger(); 21 | 22 | log.Warning("This will be written to the TraceWriter"); 23 | ``` 24 | 25 | ### Azure Functions Example 26 | 27 | You will need to include the required Nuget packages within the functions `project.json`: 28 | 29 | ```json 30 | { 31 | "frameworks": { 32 | "net46": { 33 | "dependencies": { 34 | "Serilog": "2.4.0", 35 | "Serilog.Sinks.AzureWebJobsTraceWriter": "1.0.0", 36 | "Microsoft.Azure.WebJobs": "2.1.0" 37 | } 38 | } 39 | } 40 | } 41 | ``` 42 | 43 | Then you can create a new logger within the scope of your function's static run method: 44 | 45 | ```csharp 46 | // This is required to point to the internal version of WebJobs.Host 47 | #r "Microsoft.Azure.WebJobs.Host" 48 | 49 | using System.Net; 50 | using Serilog; 51 | using Serilog.Sinks.AzureWebJobsTraceWriter; 52 | 53 | public static string Run(HttpRequestMessage req, TraceWriter log) 54 | { 55 | using (Logger logger = new LoggerConfiguration() 56 | .WriteTo.TraceWriter(log) 57 | .CreateLogger()) 58 | { 59 | 60 | string someData = Guid.NewGuid().ToString(); 61 | 62 | logger.Information("This is logging test for {someData}", someData); 63 | 64 | return $"Done with {someData}"; 65 | } 66 | } 67 | ``` 68 | 69 | ### Helpful Links 70 | 71 | * [Serilog Documentation](https://github.com/serilog/serilog/wiki) 72 | * [Azure WebJobs SDK Documentation](https://github.com/Azure/azure-webjobs-sdk/wiki) -------------------------------------------------------------------------------- /src/Serilog.Sinks.AzureWebJobsTraceWriter/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Serilog.Sinks.AzureWebJobsTraceWriter")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Serilog.Sinks.AzureWebJobsTraceWriter")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("b67a68ad-36d3-47ab-9846-a21eceada700")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | [assembly: InternalsVisibleTo("Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests")] -------------------------------------------------------------------------------- /src/Serilog.Sinks.AzureWebJobsTraceWriter/Serilog.Sinks.AzureWebJobsTraceWriter.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B67A68AD-36D3-47AB-9846-A21ECEADA700} 8 | Library 9 | Properties 10 | Serilog.Sinks.AzureWebJobsTraceWriter 11 | Serilog.Sinks.AzureWebJobsTraceWriter 12 | v4.6 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | bin\Release\Serilog.Sinks.AzureWebJobsTraceWriter.xml 33 | 34 | 35 | 36 | ..\..\packages\Microsoft.Azure.KeyVault.Core.1.0.0\lib\net40\Microsoft.Azure.KeyVault.Core.dll 37 | 38 | 39 | ..\..\packages\Microsoft.Azure.WebJobs.Core.2.1.0-beta1\lib\net45\Microsoft.Azure.WebJobs.dll 40 | 41 | 42 | ..\..\packages\Microsoft.Azure.WebJobs.2.1.0-beta1\lib\net45\Microsoft.Azure.WebJobs.Host.dll 43 | 44 | 45 | ..\..\packages\Microsoft.Data.Edm.5.6.4\lib\net40\Microsoft.Data.Edm.dll 46 | 47 | 48 | ..\..\packages\Microsoft.Data.OData.5.6.4\lib\net40\Microsoft.Data.OData.dll 49 | 50 | 51 | ..\..\packages\Microsoft.Data.Services.Client.5.6.4\lib\net40\Microsoft.Data.Services.Client.dll 52 | 53 | 54 | ..\..\packages\Microsoft.Extensions.Logging.Abstractions.1.1.1\lib\netstandard1.1\Microsoft.Extensions.Logging.Abstractions.dll 55 | 56 | 57 | ..\..\packages\WindowsAzure.Storage.7.2.1\lib\net40\Microsoft.WindowsAzure.Storage.dll 58 | 59 | 60 | ..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll 61 | 62 | 63 | ..\..\packages\Serilog.2.4.0\lib\net45\Serilog.dll 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | ..\..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll 72 | 73 | 74 | ..\..\packages\System.Spatial.5.6.4\lib\net40\System.Spatial.dll 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/Serilog.Sinks.AzureWebJobsTraceWriter/Serilog.Sinks.AzureWebJobsTraceWriter.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Serilog.Sinks.AzureWebJobsTraceWriter 5 | $version$ 6 | Serilog.Sinks.AzureWebJobsTraceWriter 7 | StarRez 8 | StarRez 9 | https://github.com/StarRez/Serilog.Sinks.AzureWebJobsTraceWriter 10 | false 11 | A Serilog sink that writes events to Azure WebJob Host's TraceWriter. 12 | Serilog Sink TraceWriter Trace Writer Azure WebJob Functions 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Serilog.Sinks.AzureWebJobsTraceWriter/Sinks/TraceWriter/TraceWriterSink.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using Microsoft.Azure.WebJobs.Host; 6 | using Serilog.Core; 7 | using Serilog.Events; 8 | using Serilog.Formatting; 9 | 10 | namespace Serilog.Sinks.AzureWebJobsTraceWriter 11 | { 12 | public class TraceWriterSink : ILogEventSink 13 | { 14 | private readonly TraceWriter m_traceWriter; 15 | private readonly ITextFormatter m_formatter; 16 | 17 | /// 18 | /// Builds a sink that can link to an Azure WebJob TraceWriter 19 | /// 20 | /// The trace writer to log to 21 | /// The formatter to use on emit 22 | public TraceWriterSink(TraceWriter traceWriter, ITextFormatter formatter) 23 | { 24 | if (traceWriter == null) 25 | { 26 | throw new ArgumentNullException(nameof(traceWriter)); 27 | } 28 | 29 | if (formatter == null) 30 | { 31 | throw new ArgumentNullException(nameof(formatter)); 32 | } 33 | 34 | m_traceWriter = traceWriter; 35 | m_formatter = formatter; 36 | } 37 | 38 | /// 39 | /// Emits an event to the underlying tracewriter 40 | /// 41 | /// The log event to emit 42 | public void Emit(LogEvent logEvent) 43 | { 44 | if (logEvent == null) 45 | { 46 | return; 47 | } 48 | 49 | TraceEvent traceEvent = BuildTraceEvent(logEvent, m_formatter); 50 | 51 | m_traceWriter.Trace(traceEvent); 52 | } 53 | 54 | internal static TraceEvent BuildTraceEvent(LogEvent logEvent, ITextFormatter formatter) 55 | { 56 | if (logEvent == null || formatter == null) 57 | { 58 | return null; 59 | } 60 | 61 | string message = FormatLogEventMessage(logEvent, formatter); 62 | 63 | TraceLevel traceLevel = GetLogEventTraceLevel(logEvent.Level); 64 | 65 | string source = GetLogEventSourceProperty(logEvent.Properties); 66 | 67 | return new TraceEvent(traceLevel, message, source, logEvent.Exception); 68 | } 69 | 70 | internal static string GetLogEventSourceProperty(IReadOnlyDictionary logEventProperties) 71 | { 72 | if (logEventProperties == null || 73 | !logEventProperties.ContainsKey(Constants.SourceContextPropertyName)) 74 | { 75 | return null; 76 | } 77 | 78 | ScalarValue sourceValue = logEventProperties[Constants.SourceContextPropertyName] as ScalarValue; 79 | 80 | return sourceValue?.Value?.ToString(); 81 | } 82 | 83 | internal static TraceLevel GetLogEventTraceLevel(LogEventLevel logEventLevel) 84 | { 85 | if (logEventLevel == LogEventLevel.Fatal || logEventLevel == LogEventLevel.Error) 86 | { 87 | return TraceLevel.Error; 88 | } 89 | 90 | if (logEventLevel == LogEventLevel.Warning) 91 | { 92 | return TraceLevel.Warning; 93 | } 94 | 95 | if (logEventLevel == LogEventLevel.Information) 96 | { 97 | return TraceLevel.Info; 98 | } 99 | 100 | return TraceLevel.Verbose; 101 | } 102 | 103 | internal static string FormatLogEventMessage(LogEvent logEvent, ITextFormatter formatter) 104 | { 105 | if (logEvent == null || formatter == null) 106 | { 107 | return null; 108 | } 109 | 110 | using (StringWriter render = new StringWriter()) 111 | { 112 | formatter.Format(logEvent, render); 113 | 114 | return render.ToString(); 115 | } 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /src/Serilog.Sinks.AzureWebJobsTraceWriter/TraceWriterLoggerConfigurationExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Azure.WebJobs.Host; 3 | using Serilog.Configuration; 4 | using Serilog.Events; 5 | using Serilog.Formatting; 6 | using Serilog.Formatting.Display; 7 | 8 | namespace Serilog.Sinks.AzureWebJobsTraceWriter 9 | { 10 | public static class TraceWriterLoggerConfigurationExtensions 11 | { 12 | private const string DefaultOutputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}"; 13 | 14 | public static LoggerConfiguration TraceWriter( 15 | this LoggerSinkConfiguration loggerConfiguration, 16 | TraceWriter traceWriter, 17 | string outputTemplate = DefaultOutputTemplate, 18 | IFormatProvider formatProvider = null, 19 | LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) 20 | { 21 | if (loggerConfiguration == null) 22 | { 23 | throw new ArgumentNullException(nameof(loggerConfiguration)); 24 | } 25 | 26 | if (traceWriter == null) 27 | { 28 | throw new ArgumentNullException(nameof(traceWriter)); 29 | } 30 | 31 | if (outputTemplate == null) 32 | { 33 | throw new ArgumentNullException(nameof(outputTemplate)); 34 | } 35 | 36 | ITextFormatter formatter = new MessageTemplateTextFormatter(outputTemplate, formatProvider); 37 | 38 | return TraceWriter(loggerConfiguration, traceWriter, formatter, restrictedToMinimumLevel); 39 | } 40 | 41 | public static LoggerConfiguration TraceWriter( 42 | this LoggerSinkConfiguration loggerConfiguration, 43 | TraceWriter traceWriter, 44 | ITextFormatter formatter, 45 | LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum) 46 | { 47 | if (loggerConfiguration == null) 48 | { 49 | throw new ArgumentNullException(nameof(loggerConfiguration)); 50 | } 51 | 52 | if (traceWriter == null) 53 | { 54 | throw new ArgumentNullException(nameof(traceWriter)); 55 | } 56 | 57 | if (formatter == null) 58 | { 59 | throw new ArgumentNullException(nameof(formatter)); 60 | } 61 | 62 | TraceWriterSink sink = new TraceWriterSink(traceWriter, formatter); 63 | 64 | return loggerConfiguration.Sink(sink, restrictedToMinimumLevel); 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/Serilog.Sinks.AzureWebJobsTraceWriter/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Serilog.Sinks.AzureWebJobsTraceWriter/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /test.ps1: -------------------------------------------------------------------------------- 1 | $codeCoverageFile = "CodeCoverage.runsettings" 2 | $coverageXmlFile = "TestResults\coverage.coveragexml" 3 | 4 | $xunitRunnerVSPath = (Resolve-Path ".\packages\xunit.runner.visualstudio.*\build\_common\").Path 5 | $coverallsPath = (Resolve-Path ".\packages\coveralls.net.*\tools\csmacnz.coveralls.exe").Path 6 | 7 | $unitTestsPath = ".\tests\Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests\bin\Release\Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests.dll" 8 | 9 | $vsCodeCoverageExe = "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Team Tools\Dynamic Code Coverage Tools\CodeCoverage.exe" 10 | 11 | if (!(Test-Path -Path $vsCodeCoverageExe)) 12 | { 13 | $vsCodeCoverageExe = "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Dynamic Code Coverage Tools\CodeCoverage.exe" 14 | } 15 | 16 | # Cleanup before we start 17 | 18 | if (Test-Path -Path "TestResults\") 19 | { 20 | Remove-Item -Path "TestResults\" -Recurse -Force 21 | } 22 | if (Test-Path -Path ".\$coverageXmlFile") 23 | { 24 | Remove-Item -Path ".\$coverageXmlFile" 25 | } 26 | if (Test-Path -Path ".\$coverageXmlFile") 27 | { 28 | Remove-Item -Path ".\$coverageXmlFile" 29 | } 30 | 31 | vstest.console.exe /inIsolation /Enablecodecoverage /TestAdapterPath:"$xunitRunnerVSPath" /Settings:$codeCoverageFile /logger:Appveyor "$unitTestsPath" 32 | 33 | $coverageFilePath = (Resolve-Path -path "TestResults\*\*.coverage").Path 34 | 35 | if (Test-Path -Path $coverageXmlFile) 36 | { 37 | Remove-Item -Path $coverageXmlFile 38 | } 39 | 40 | & $vsCodeCoverageExe analyze /output:$coverageXmlFile "$coverageFilePath" 41 | 42 | & $coverallsPath --dynamiccodecoverage -i $coverageXmlFile --repoToken $env:COVERALLS_REPO_TOKEN --commitId $env:APPVEYOR_REPO_COMMIT --commitBranch $env:APPVEYOR_REPO_BRANCH --commitAuthor $env:APPVEYOR_REPO_COMMIT_AUTHOR --commitEmail $env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL --commitMessage $env:APPVEYOR_REPO_COMMIT_MESSAGE --jobId $env:APPVEYOR_JOB_ID --useRelativePaths -------------------------------------------------------------------------------- /tests/Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests/Helpers/InMemoryTraceWriter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using System.Diagnostics.CodeAnalysis; 4 | using Microsoft.Azure.WebJobs.Host; 5 | 6 | namespace Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests 7 | { 8 | [ExcludeFromCodeCoverage] 9 | internal class InMemoryTraceWriter : TraceWriter 10 | { 11 | private readonly List m_events; 12 | 13 | public IReadOnlyCollection Events 14 | { 15 | get 16 | { 17 | return m_events.AsReadOnly(); 18 | } 19 | } 20 | 21 | public InMemoryTraceWriter(TraceLevel level) : base(level) 22 | { 23 | m_events = new List(); 24 | } 25 | 26 | public override void Trace(TraceEvent traceEvent) 27 | { 28 | m_events.Add(traceEvent); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /tests/Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests/Helpers/LogEventHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Linq; 4 | using Serilog.Events; 5 | using Serilog.Parsing; 6 | 7 | namespace Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests 8 | { 9 | [ExcludeFromCodeCoverage] 10 | internal class LogEventHelper 11 | { 12 | public static LogEvent GetLogEvent() 13 | { 14 | return GetLogEvent(nameof(GetLogEvent)); 15 | } 16 | 17 | public static LogEvent GetLogEvent(string message) 18 | { 19 | return GetLogEvent(message, LogEventLevel.Information); 20 | } 21 | 22 | public static LogEvent GetLogEvent(string message, LogEventLevel level) 23 | { 24 | MessageTemplate template = new MessageTemplateParser().Parse(message); 25 | 26 | return new LogEvent(DateTimeOffset.Now, level, null, template, Enumerable.Empty()); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /tests/Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | [assembly: AssemblyTitle("Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests")] 5 | [assembly: AssemblyDescription("")] 6 | [assembly: AssemblyConfiguration("")] 7 | [assembly: AssemblyCompany("")] 8 | [assembly: AssemblyProduct("Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests")] 9 | [assembly: AssemblyCopyright("Copyright © 2017")] 10 | [assembly: AssemblyTrademark("")] 11 | [assembly: AssemblyCulture("")] 12 | [assembly: ComVisible(false)] 13 | [assembly: Guid("b9938905-c77e-43d6-9591-22178dff6c02")] 14 | 15 | // [assembly: AssemblyVersion("1.0.*")] 16 | [assembly: AssemblyVersion("1.0.0.0")] 17 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /tests/Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests/Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {B9938905-C77E-43D6-9591-22178DFF6C02} 9 | Library 10 | Properties 11 | Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests 12 | Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests 13 | v4.6 14 | 512 15 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 16 | 15.0 17 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 18 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 19 | False 20 | UnitTest 21 | 22 | 23 | 24 | 25 | 26 | true 27 | full 28 | false 29 | bin\Debug\ 30 | DEBUG;TRACE 31 | prompt 32 | 4 33 | 34 | 35 | pdbonly 36 | true 37 | bin\Release\ 38 | TRACE 39 | prompt 40 | 4 41 | 42 | 43 | 44 | ..\..\packages\Microsoft.Azure.KeyVault.Core.1.0.0\lib\net40\Microsoft.Azure.KeyVault.Core.dll 45 | 46 | 47 | ..\..\packages\Microsoft.Azure.WebJobs.Core.2.1.0-beta1\lib\net45\Microsoft.Azure.WebJobs.dll 48 | 49 | 50 | ..\..\packages\Microsoft.Azure.WebJobs.2.1.0-beta1\lib\net45\Microsoft.Azure.WebJobs.Host.dll 51 | 52 | 53 | ..\..\packages\Microsoft.Data.Edm.5.6.4\lib\net40\Microsoft.Data.Edm.dll 54 | 55 | 56 | ..\..\packages\Microsoft.Data.OData.5.6.4\lib\net40\Microsoft.Data.OData.dll 57 | 58 | 59 | ..\..\packages\Microsoft.Data.Services.Client.5.6.4\lib\net40\Microsoft.Data.Services.Client.dll 60 | 61 | 62 | ..\..\packages\Microsoft.Extensions.Logging.Abstractions.1.1.1\lib\netstandard1.1\Microsoft.Extensions.Logging.Abstractions.dll 63 | 64 | 65 | ..\..\packages\MSTest.TestFramework.1.1.11\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll 66 | 67 | 68 | ..\..\packages\MSTest.TestFramework.1.1.11\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll 69 | 70 | 71 | ..\..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll 72 | 73 | 74 | ..\..\packages\WindowsAzure.Storage.7.2.1\lib\net40\Microsoft.WindowsAzure.Storage.dll 75 | 76 | 77 | ..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll 78 | 79 | 80 | ..\..\packages\Serilog.2.4.0\lib\net45\Serilog.dll 81 | 82 | 83 | 84 | ..\..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll 85 | 86 | 87 | 88 | ..\..\packages\System.Console.4.3.0\lib\net46\System.Console.dll 89 | 90 | 91 | 92 | 93 | ..\..\packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll 94 | 95 | 96 | ..\..\packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll 97 | 98 | 99 | ..\..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll 100 | True 101 | 102 | 103 | 104 | ..\..\packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll 105 | 106 | 107 | ..\..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll 108 | 109 | 110 | ..\..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll 111 | 112 | 113 | ..\..\packages\System.Net.Http.4.3.0\lib\net46\System.Net.Http.dll 114 | 115 | 116 | ..\..\packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll 117 | 118 | 119 | 120 | ..\..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll 121 | True 122 | 123 | 124 | ..\..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net46\System.Security.Cryptography.Algorithms.dll 125 | 126 | 127 | ..\..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll 128 | 129 | 130 | ..\..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll 131 | 132 | 133 | ..\..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net46\System.Security.Cryptography.X509Certificates.dll 134 | 135 | 136 | ..\..\packages\System.Spatial.5.6.4\lib\net40\System.Spatial.dll 137 | 138 | 139 | 140 | 141 | ..\..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll 142 | 143 | 144 | ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll 145 | 146 | 147 | ..\..\packages\xunit.assert.2.2.0\lib\netstandard1.1\xunit.assert.dll 148 | 149 | 150 | ..\..\packages\xunit.extensibility.core.2.2.0\lib\netstandard1.1\xunit.core.dll 151 | 152 | 153 | ..\..\packages\xunit.extensibility.execution.2.2.0\lib\net452\xunit.execution.desktop.dll 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | {b67a68ad-36d3-47ab-9846-a21eceada700} 170 | Serilog.Sinks.AzureWebJobsTraceWriter 171 | 172 | 173 | 174 | 175 | 176 | 177 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 178 | 179 | 180 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /tests/Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests/TraceWriterLoggerConfigurationExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Linq; 6 | using Microsoft.Azure.WebJobs.Host; 7 | using Serilog.Events; 8 | using Serilog.Formatting; 9 | using Serilog.Formatting.Display; 10 | using Serilog.Formatting.Raw; 11 | using Xunit; 12 | 13 | namespace Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests 14 | { 15 | [ExcludeFromCodeCoverage] 16 | public class TraceWriterLoggerConfigurationExtensionsTests 17 | { 18 | [Fact] 19 | public void TraceWriter_ITextFormatter_NullLoggerConfiguration() 20 | { 21 | Assert.Throws(() => 22 | { 23 | InMemoryTraceWriter traceWriter = new InMemoryTraceWriter(TraceLevel.Verbose); 24 | 25 | ITextFormatter formatter = new RawFormatter(); 26 | 27 | TraceWriterLoggerConfigurationExtensions.TraceWriter(null, traceWriter, formatter); 28 | }); 29 | } 30 | 31 | [Fact] 32 | public void TraceWriter_ITextFormatter_NullTraceWriter() 33 | { 34 | Assert.Throws(() => 35 | { 36 | LoggerConfiguration loggerConfiguration = new LoggerConfiguration(); 37 | 38 | ITextFormatter formatter = new RawFormatter(); 39 | 40 | TraceWriterLoggerConfigurationExtensions.TraceWriter(loggerConfiguration.WriteTo, null, formatter); 41 | }); 42 | } 43 | 44 | [Fact] 45 | public void TraceWriter_ITextFormatter_NullFormatter() 46 | { 47 | Assert.Throws(() => 48 | { 49 | LoggerConfiguration loggerConfiguration = new LoggerConfiguration(); 50 | 51 | InMemoryTraceWriter traceWriter = new InMemoryTraceWriter(TraceLevel.Verbose); 52 | 53 | ITextFormatter formatter = null; 54 | 55 | TraceWriterLoggerConfigurationExtensions.TraceWriter(loggerConfiguration.WriteTo, traceWriter, formatter); 56 | }); 57 | } 58 | 59 | [Fact] 60 | public void TraceWriter_IFormatProvider_NullLoggerConfiguration() 61 | { 62 | Assert.Throws(() => 63 | { 64 | InMemoryTraceWriter traceWriter = new InMemoryTraceWriter(TraceLevel.Verbose); 65 | 66 | TraceWriterLoggerConfigurationExtensions.TraceWriter(null, traceWriter); 67 | }); 68 | } 69 | 70 | [Fact] 71 | public void TraceWriter_IFormatProvider_NullTraceWriter() 72 | { 73 | Assert.Throws(() => 74 | { 75 | LoggerConfiguration loggerConfiguration = new LoggerConfiguration(); 76 | 77 | TraceWriterLoggerConfigurationExtensions.TraceWriter(loggerConfiguration.WriteTo, null); 78 | }); 79 | } 80 | 81 | [Fact] 82 | public void TraceWriter_IFormatProvider_NullOutputTemplate() 83 | { 84 | Assert.Throws(() => 85 | { 86 | LoggerConfiguration loggerConfiguration = new LoggerConfiguration(); 87 | 88 | InMemoryTraceWriter traceWriter = new InMemoryTraceWriter(TraceLevel.Verbose); 89 | 90 | string outputTemplate = null; 91 | 92 | TraceWriterLoggerConfigurationExtensions.TraceWriter(loggerConfiguration.WriteTo, traceWriter, outputTemplate); 93 | }); 94 | } 95 | 96 | [Theory, MemberData(nameof(TraceWriter_TestData))] 97 | public void TraceWriter_ITextFormatter_NonExtensionCallPattern(Func loggerAction) 98 | { 99 | string message = "Hello, World!"; 100 | 101 | // Need to explicity define lowest level. 102 | LoggerConfiguration loggerConfiguration = new LoggerConfiguration().MinimumLevel.Verbose(); 103 | 104 | InMemoryTraceWriter traceWriter = new InMemoryTraceWriter(TraceLevel.Verbose); 105 | 106 | ITextFormatter formatter = new MessageTemplateTextFormatter("{Message}", null); 107 | 108 | loggerConfiguration = TraceWriterLoggerConfigurationExtensions.TraceWriter(loggerConfiguration.WriteTo, traceWriter, formatter, LogEventLevel.Verbose); 109 | 110 | ILogger logger = loggerConfiguration.CreateLogger(); 111 | 112 | Assert.Equal(0, traceWriter.Events.Count); 113 | 114 | TraceLevel expectedTraceLevel = loggerAction(logger, message); 115 | 116 | Assert.Equal(1, traceWriter.Events.Count); 117 | 118 | TraceEvent traceEvent = traceWriter.Events.First(); 119 | 120 | Assert.Equal(message, traceEvent.Message); 121 | Assert.Equal(expectedTraceLevel, traceEvent.Level); 122 | } 123 | 124 | [Theory, MemberData(nameof(TraceWriter_TestData))] 125 | public void TraceWriter_ITextFormatter(Func loggerAction) 126 | { 127 | string message = "Hello, World!"; 128 | 129 | // Need to explicity define lowest level. 130 | LoggerConfiguration loggerConfiguration = new LoggerConfiguration().MinimumLevel.Verbose(); 131 | 132 | InMemoryTraceWriter traceWriter = new InMemoryTraceWriter(TraceLevel.Verbose); 133 | 134 | ITextFormatter formatter = new MessageTemplateTextFormatter("{Message}", null); 135 | 136 | loggerConfiguration = loggerConfiguration.WriteTo.TraceWriter(traceWriter, formatter); 137 | 138 | ILogger logger = loggerConfiguration.CreateLogger(); 139 | 140 | Assert.Equal(0, traceWriter.Events.Count); 141 | 142 | TraceLevel expectedTraceLevel = loggerAction(logger, message); 143 | 144 | Assert.Equal(1, traceWriter.Events.Count); 145 | 146 | TraceEvent traceEvent = traceWriter.Events.First(); 147 | 148 | Assert.Equal(message, traceEvent.Message); 149 | Assert.Equal(expectedTraceLevel, traceEvent.Level); 150 | } 151 | 152 | [Theory, MemberData(nameof(TraceWriter_TestData))] 153 | public void TraceWriter_IFormatProvider(Func loggerAction) 154 | { 155 | string message = "Hello, World!"; 156 | 157 | // Need to explicity define lowest level. 158 | LoggerConfiguration loggerConfiguration = new LoggerConfiguration().MinimumLevel.Verbose(); 159 | 160 | InMemoryTraceWriter traceWriter = new InMemoryTraceWriter(TraceLevel.Verbose); 161 | 162 | loggerConfiguration = loggerConfiguration.WriteTo.TraceWriter(traceWriter, "{Message}"); 163 | 164 | ILogger logger = loggerConfiguration.CreateLogger(); 165 | 166 | Assert.Equal(0, traceWriter.Events.Count); 167 | 168 | TraceLevel expectedTraceLevel = loggerAction(logger, message); 169 | 170 | Assert.Equal(1, traceWriter.Events.Count); 171 | 172 | TraceEvent traceEvent = traceWriter.Events.First(); 173 | 174 | Assert.Equal(message, traceEvent.Message); 175 | Assert.Equal(expectedTraceLevel, traceEvent.Level); 176 | } 177 | 178 | public static IEnumerable TraceWriter_TestData 179 | { 180 | get 181 | { 182 | return new Func[] 183 | { 184 | (logger, message) => { logger.Fatal(message); return TraceLevel.Error; }, 185 | (logger, message) => { logger.Error(message); return TraceLevel.Error; }, 186 | (logger, message) => { logger.Warning(message); return TraceLevel.Warning; }, 187 | (logger, message) => { logger.Information(message); return TraceLevel.Info; }, 188 | (logger, message) => { logger.Verbose(message); return TraceLevel.Verbose; }, 189 | (logger, message) => { logger.Debug(message); return TraceLevel.Verbose; } 190 | }.Select(x => new object[] { x }); 191 | } 192 | } 193 | } 194 | } -------------------------------------------------------------------------------- /tests/Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests/TraceWriterSinkTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Linq; 6 | using Microsoft.Azure.WebJobs.Host; 7 | using Serilog.Core; 8 | using Serilog.Events; 9 | using Serilog.Formatting; 10 | using Serilog.Formatting.Display; 11 | using Serilog.Formatting.Raw; 12 | using Xunit; 13 | 14 | namespace Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests 15 | { 16 | [ExcludeFromCodeCoverage] 17 | public class TraceWriterSinkTests 18 | { 19 | [Fact] 20 | public void Constructor_NullTraceWriter() 21 | { 22 | Assert.Throws(() => 23 | { 24 | ITextFormatter formatter = new RawFormatter(); 25 | 26 | TraceWriterSink t = new TraceWriterSink(null, formatter); 27 | }); 28 | } 29 | 30 | [Fact] 31 | public void Constructor_NullFormatter() 32 | { 33 | Assert.Throws(() => 34 | { 35 | TraceWriter traceWriter = new InMemoryTraceWriter(TraceLevel.Verbose); 36 | 37 | TraceWriterSink t = new TraceWriterSink(traceWriter, null); 38 | }); 39 | } 40 | 41 | [Fact] 42 | public void Constructor() 43 | { 44 | TraceWriter traceWriter = new InMemoryTraceWriter(TraceLevel.Verbose); 45 | ITextFormatter formatter = new RawFormatter(); 46 | 47 | TraceWriterSink t = new TraceWriterSink(traceWriter, formatter); 48 | } 49 | 50 | [Theory] 51 | [InlineData(LogEventLevel.Fatal, TraceLevel.Error)] 52 | [InlineData(LogEventLevel.Error, TraceLevel.Error)] 53 | [InlineData(LogEventLevel.Warning, TraceLevel.Warning)] 54 | [InlineData(LogEventLevel.Information, TraceLevel.Info)] 55 | [InlineData(LogEventLevel.Verbose, TraceLevel.Verbose)] 56 | [InlineData(LogEventLevel.Debug, TraceLevel.Verbose)] 57 | public void GetLogEventTraceLevel(LogEventLevel logEventLevel, TraceLevel expectedTraceLevel) 58 | { 59 | TraceLevel traceLevel = TraceWriterSink.GetLogEventTraceLevel(logEventLevel); 60 | 61 | Assert.Equal(expectedTraceLevel, traceLevel); 62 | } 63 | 64 | [Fact] 65 | public void FormatLogEventMessage() 66 | { 67 | string message = "PlainMessageTemplate"; 68 | 69 | LogEvent logEvent = LogEventHelper.GetLogEvent(message); 70 | 71 | ITextFormatter formatter = new MessageTemplateTextFormatter("{Message}", null); 72 | 73 | string formattedMessage = TraceWriterSink.FormatLogEventMessage(logEvent, formatter); 74 | 75 | Assert.Equal(message, formattedMessage); 76 | } 77 | 78 | [Fact] 79 | public void FormatLogEventMessage_NullLogEvent() 80 | { 81 | ITextFormatter formatter = new RawFormatter(); 82 | 83 | string formattedMessage = TraceWriterSink.FormatLogEventMessage(null, formatter); 84 | 85 | Assert.Null(formattedMessage); 86 | } 87 | 88 | [Fact] 89 | public void FormatLogEventMessage_NullFormatter() 90 | { 91 | LogEvent logEvent = LogEventHelper.GetLogEvent(); 92 | 93 | string formattedMessage = TraceWriterSink.FormatLogEventMessage(logEvent, null); 94 | 95 | Assert.Null(formattedMessage); 96 | } 97 | 98 | [Fact] 99 | public void GetLogEventSourceProperty() 100 | { 101 | string expectedSource = "SomeSource"; 102 | 103 | Dictionary propertyValues = new Dictionary 104 | { 105 | { Constants.SourceContextPropertyName, new ScalarValue(expectedSource) } 106 | }; 107 | 108 | string source = TraceWriterSink.GetLogEventSourceProperty(propertyValues); 109 | 110 | Assert.Equal(expectedSource, source); 111 | } 112 | 113 | [Fact] 114 | public void GetLogEventSourceProperty_NotInPropertyValues() 115 | { 116 | Dictionary propertyValues = new Dictionary(); 117 | 118 | string source = TraceWriterSink.GetLogEventSourceProperty(propertyValues); 119 | 120 | Assert.Null(source); 121 | } 122 | 123 | [Fact] 124 | public void GetLogEventSourceProperty_NotAScalarValue() 125 | { 126 | Dictionary propertyValues = new Dictionary 127 | { 128 | { Constants.SourceContextPropertyName, null } 129 | }; 130 | 131 | string source = TraceWriterSink.GetLogEventSourceProperty(propertyValues); 132 | 133 | Assert.Null(source); 134 | } 135 | 136 | [Fact] 137 | public void GetLogEventSourceProperty_NullScalarValue() 138 | { 139 | Dictionary propertyValues = new Dictionary 140 | { 141 | { Constants.SourceContextPropertyName, new ScalarValue(null) } 142 | }; 143 | 144 | string source = TraceWriterSink.GetLogEventSourceProperty(propertyValues); 145 | 146 | Assert.Null(source); 147 | } 148 | 149 | [Fact] 150 | public void GetLogEventSourceProperty_NullLogEventProperties() 151 | { 152 | string source = TraceWriterSink.GetLogEventSourceProperty(null); 153 | 154 | Assert.Null(source); 155 | } 156 | 157 | [Fact] 158 | public void BuildTraceEvent_NullLogEvent() 159 | { 160 | ITextFormatter formatter = new RawFormatter(); 161 | 162 | TraceEvent traceEvent = TraceWriterSink.BuildTraceEvent(null, formatter); 163 | 164 | Assert.Null(traceEvent); 165 | } 166 | 167 | [Fact] 168 | public void BuildTraceEvent_NullFormatter() 169 | { 170 | LogEvent logEvent = LogEventHelper.GetLogEvent(); 171 | 172 | TraceEvent traceEvent = TraceWriterSink.BuildTraceEvent(logEvent, null); 173 | 174 | Assert.Null(traceEvent); 175 | } 176 | 177 | [Fact] 178 | public void BuildTraceEvent() 179 | { 180 | string message = "PlainMessageTemplate"; 181 | 182 | LogEventLevel logEventLevel = LogEventLevel.Warning; 183 | TraceLevel expectedTraceLevel = TraceLevel.Warning; 184 | 185 | LogEvent logEvent = LogEventHelper.GetLogEvent(message, logEventLevel); 186 | 187 | ITextFormatter formatter = new MessageTemplateTextFormatter("{Message}", null); 188 | 189 | TraceEvent traceEvent = TraceWriterSink.BuildTraceEvent(logEvent, formatter); 190 | 191 | Assert.Equal(message, traceEvent.Message); 192 | Assert.Equal(expectedTraceLevel, traceEvent.Level); 193 | } 194 | 195 | [Fact] 196 | public void Emit_NullLogEvent() 197 | { 198 | InMemoryTraceWriter traceWriter = new InMemoryTraceWriter(TraceLevel.Verbose); 199 | 200 | ITextFormatter formatter = new RawFormatter(); 201 | 202 | TraceWriterSink sink = new TraceWriterSink(traceWriter, formatter); 203 | 204 | Assert.Equal(0, traceWriter.Events.Count); 205 | 206 | sink.Emit(null); 207 | 208 | Assert.Equal(0, traceWriter.Events.Count); 209 | } 210 | 211 | [Fact] 212 | public void Emit() 213 | { 214 | string message = "PlainMessageTemplate"; 215 | 216 | LogEventLevel logEventLevel = LogEventLevel.Warning; 217 | TraceLevel expectedTraceLevel = TraceLevel.Warning; 218 | 219 | LogEvent logEvent = LogEventHelper.GetLogEvent(message, logEventLevel); 220 | 221 | ITextFormatter formatter = new MessageTemplateTextFormatter("{Message}", null); 222 | 223 | InMemoryTraceWriter traceWriter = new InMemoryTraceWriter(TraceLevel.Verbose); 224 | 225 | TraceWriterSink sink = new TraceWriterSink(traceWriter, formatter); 226 | 227 | Assert.Equal(0, traceWriter.Events.Count); 228 | 229 | sink.Emit(logEvent); 230 | 231 | Assert.Equal(1, traceWriter.Events.Count); 232 | 233 | TraceEvent traceEvent = traceWriter.Events.First(); 234 | 235 | Assert.Equal(message, traceEvent.Message); 236 | Assert.Equal(expectedTraceLevel, traceEvent.Level); 237 | } 238 | } 239 | } -------------------------------------------------------------------------------- /tests/Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/Serilog.Sinks.AzureWebJobsTraceWriter.UnitTests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | --------------------------------------------------------------------------------