diff --git a/README.md b/README.md index 549e949ef8799c10c136f6b8b4f26bb4c991a977..8e9f8be065f414ded781d1c57502a4717d4023f6 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,19 @@ ## C# Template -This template includes: - -* Automatic building using cake -* Automatic testing with NUnit -* Automatic linting with Resharper -* Automatic documentation publishing using Gitlab CI / CD and a self written script which puts the docs in the docs folder to the wiki -* Automatic releases using semantic-release ([ESLint Code Convention](docs/ESLintConvention)), cake and Gitlab CI / CD - -## What you need to do - -Place you C# project solution file in .src/. -Make sure Create directory for solution is unticked. - - - -Delete unused docs and update this README. - -Add [NUnit](docs/nunit.md) tests to your solution. - -## Building - -Build this project by running either the build.ps1 or the build<span></span>.sh script. -The project will be build and tested. - -### Links - -* [Commit convention](docs/ESLintConvention.md) -* [Everything possible with markup](docs/testdoc.md) -* [Adding NUnit tests](docs/nunit.md) \ No newline at end of file +C# library allowing logging. + +Example for including custom log messages: Add the following code to the required Api controller constructor and add the logger calls where needed: + +``` + public class ProjectController : Controller + { + ... + private readonly CoscineLogger _logger; + + public ProjectController(ILogger<LicenseController> ilogger) + { + ... + _logger = new CoscineLogger(ilogger); + _logger.Log(LogType.Reporting, "Example log message"); + } +``` \ No newline at end of file diff --git a/src/Logging.Tests/App.config b/src/Logging.Tests/App.config new file mode 100644 index 0000000000000000000000000000000000000000..e78ba33fd003204d4d38a776fb4109abe0bce6db --- /dev/null +++ b/src/Logging.Tests/App.config @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<configuration> + <startup> + <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /> + </startup> + <runtime> + <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Extensions.Configuration.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Extensions.Primitives" publicKeyToken="adb9793829ddae60" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Extensions.Options" publicKeyToken="adb9793829ddae60" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-2.1.1.0" newVersion="2.1.1.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-2.1.1.0" newVersion="2.1.1.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /> + </dependentAssembly> + </assemblyBinding> + </runtime> +</configuration> \ No newline at end of file diff --git a/src/Logging.Tests/Logging.Tests.csproj b/src/Logging.Tests/Logging.Tests.csproj new file mode 100644 index 0000000000000000000000000000000000000000..9a7030e68ebfc105beb913715b49b661488432ea --- /dev/null +++ b/src/Logging.Tests/Logging.Tests.csproj @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="..\packages\NUnit.3.12.0\build\NUnit.props" Condition="Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" /> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{7F9F01BD-F755-4BFE-B58D-073AA4F8EACE}</ProjectGuid> + <OutputType>Library</OutputType> + <RootNamespace>Logging.Tests</RootNamespace> + <AssemblyName>Logging.Tests</AssemblyName> + <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> + <Deterministic>true</Deterministic> + <NuGetPackageImportStamp> + </NuGetPackageImportStamp> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <PlatformTarget>AnyCPU</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <PlatformTarget>AnyCPU</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="Consul, Version=0.7.2.6, Culture=neutral, PublicKeyToken=20a6ad9a81df1d95, processorArchitecture=MSIL"> + <HintPath>..\packages\Consul.0.7.2.6\lib\net45\Consul.dll</HintPath> + </Reference> + <Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL"> + <HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath> + </Reference> + <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL"> + <HintPath>..\packages\NLog.4.6.8\lib\net45\NLog.dll</HintPath> + </Reference> + <Reference Include="nunit.framework, Version=3.12.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL"> + <HintPath>..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.ComponentModel.DataAnnotations" /> + <Reference Include="System.Configuration" /> + <Reference Include="System.Core" /> + <Reference Include="System.IO.Compression" /> + <Reference Include="System.Net.Http.WebRequest" /> + <Reference Include="System.Numerics" /> + <Reference Include="System.Runtime.Serialization" /> + <Reference Include="System.ServiceModel" /> + <Reference Include="System.Transactions" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Net.Http" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="LoggingTests.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <None Include="App.config" /> + <None Include="packages.config" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\Logging\Logging.csproj"> + <Project>{c7025063-054b-4e19-81dc-353df49adb3a}</Project> + <Name>Logging</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>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}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit.3.12.0\build\NUnit.props'))" /> + </Target> +</Project> \ No newline at end of file diff --git a/src/Logging.Tests/LoggingTests.cs b/src/Logging.Tests/LoggingTests.cs new file mode 100644 index 0000000000000000000000000000000000000000..2279212208406d276c466922e425cda032cabf21 --- /dev/null +++ b/src/Logging.Tests/LoggingTests.cs @@ -0,0 +1,15 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Coscine.Logging.Tests +{ + [TestFixture] + class LoggingTests + { + + } +} diff --git a/src/Logging.Tests/Properties/AssemblyInfo.cs b/src/Logging.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000000000000000000000000000000000..a17d040e1c88cfe8f77cf4a6568f73f501259a14 --- /dev/null +++ b/src/Logging.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Logging.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Logging.Tests")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7f9f01bd-f755-4bfe-b58d-073aa4f8eace")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Logging.Tests/packages.config b/src/Logging.Tests/packages.config new file mode 100644 index 0000000000000000000000000000000000000000..3a29883529fc50460bdb1d9b3a452bd99cb20e8d --- /dev/null +++ b/src/Logging.Tests/packages.config @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="Consul" version="0.7.2.6" targetFramework="net472" /> + <package id="Microsoft.Extensions.Logging.Abstractions" version="2.2.0" targetFramework="net461" /> + <package id="NLog" version="4.6.8" targetFramework="net472" /> + <package id="NLog.Config" version="4.6.8" targetFramework="net472" /> + <package id="NLog.Schema" version="4.6.8" targetFramework="net472" /> + <package id="NUnit" version="3.12.0" targetFramework="net472" /> +</packages> \ No newline at end of file diff --git a/src/Logging.sln b/src/Logging.sln new file mode 100644 index 0000000000000000000000000000000000000000..caefc87d18bd8ce0d08120d3274ac1cb7b0ff059 --- /dev/null +++ b/src/Logging.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29209.62 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Logging", "Logging\Logging.csproj", "{C7025063-054B-4E19-81DC-353DF49ADB3A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Logging.Tests", "Logging.Tests\Logging.Tests.csproj", "{7F9F01BD-F755-4BFE-B58D-073AA4F8EACE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C7025063-054B-4E19-81DC-353DF49ADB3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7025063-054B-4E19-81DC-353DF49ADB3A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7025063-054B-4E19-81DC-353DF49ADB3A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7025063-054B-4E19-81DC-353DF49ADB3A}.Release|Any CPU.Build.0 = Release|Any CPU + {7F9F01BD-F755-4BFE-B58D-073AA4F8EACE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7F9F01BD-F755-4BFE-B58D-073AA4F8EACE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F9F01BD-F755-4BFE-B58D-073AA4F8EACE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7F9F01BD-F755-4BFE-B58D-073AA4F8EACE}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2E390C97-9D7F-49FD-89E8-792C1C9419BF} + EndGlobalSection +EndGlobal diff --git a/src/Logging/App.config b/src/Logging/App.config new file mode 100644 index 0000000000000000000000000000000000000000..194d1134349f22d87cf3b5e4c4e9c31446a1ecdb --- /dev/null +++ b/src/Logging/App.config @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<configuration> + <startup> + <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /> + </startup> + <runtime> + <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Extensions.Configuration.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Extensions.Logging" publicKeyToken="adb9793829ddae60" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Extensions.Primitives" publicKeyToken="adb9793829ddae60" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Extensions.Options" publicKeyToken="adb9793829ddae60" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" /> + </dependentAssembly> + </assemblyBinding> + </runtime> +</configuration> \ No newline at end of file diff --git a/src/Logging/Coscine.Logging.snk b/src/Logging/Coscine.Logging.snk new file mode 100644 index 0000000000000000000000000000000000000000..094e9cb3cc2a8dee6872ba408dc8cb29b9539dfe Binary files /dev/null and b/src/Logging/Coscine.Logging.snk differ diff --git a/src/Logging/CoscineLogger.cs b/src/Logging/CoscineLogger.cs new file mode 100644 index 0000000000000000000000000000000000000000..200114aff9ace015f8257121d8c70d2a5d536ccf --- /dev/null +++ b/src/Logging/CoscineLogger.cs @@ -0,0 +1,402 @@ +using NLog; +using System; +using System.Diagnostics; +using System.Text; +using NLog.Targets; +using Consul; +using LogLevel = NLog.LogLevel; +using System.Text.RegularExpressions; +using NLog.Config; +using Microsoft.Extensions.Logging; +using NLog.LayoutRenderers; + +namespace Coscine.Logging +{ + + public class CoscineLogger + { + private readonly Microsoft.Extensions.Logging.ILogger _logger; + + private const LogType defaultLogType = LogType.Low; + + private static bool[] activeLoglevels = new bool[Enum.GetNames(typeof(LogType)).Length]; + + // Keys for the database string + private const string DbDataSourceKey = "coscine/global/db_data_source"; + private const string DbNameKey = "coscine/global/db_name"; + private const string DbUserIdKey = "coscine/global/db_user_id"; + private const string DbPasswordKey = "coscine/global/db_password"; + + // path for the file logger + private const string FileLoggerPath = "coscine/global/logging/fileloggerpath"; + + // keys for the loglevels + private const string LogLevelKeyDebug = "coscine/global/logging/levels/debug"; + private const string LogLevelKeyLow = "coscine/global/logging/levels/low"; + private const string LogLevelKeyMedium = "coscine/global/logging/levels/medium"; + private const string LogLevelKeyHigh = "coscine/global/logging/levels/high"; + private const string LogLevelKeyCritical = "coscine/global/logging/levels/critical"; + private const string LogLevelKeyAnalytics = "coscine/global/logging/levels/analytics"; + private const string LogLevelKeyReporting = "coscine/global/logging/levels/reporting"; + + + public CoscineLogger(Microsoft.Extensions.Logging.ILogger logger) + { + UpdateActiveLogs(); + _logger = logger; + } + + public static void SetConfig() + { + LayoutRenderer.Register<LogLevelLayoutRenderer>("CoscineLogLevel"); + + var config = new LoggingConfiguration(); + + + var targetFileLogger = new FileTarget + { + Name = "fileTarget", + FileName = GetStringFromConsul(FileLoggerPath), + Layout = "${date:universalTime=true}|${mdlc:ClientTimeStamp}|${CoscineLogLevel}|${message}|${mdlc:User}|${mdlc:Uri}|${machinename}|${activityid}|${mdlc:Status}|${callsite}|${exception:format=message}${exception:format=stackTrace}" + }; + + + var targetDatabase = new DatabaseTarget + { + Name = "database", + ConnectionString = CoscineLogger.GetDbConnectionString(), + CommandText = @"insert into dbo.Log ( [ServerTimeStamp], [ClientTimeStamp], [LogLevel], [Message], [Stacktrace], [UserId], [URI], [Server], [CorrolationId], [Status], [Source]) + values ( + CAST( @serverTimeStamp AS DATETIME2), + CASE WHEN @clientTimeStamp = '' THEN NULL ELSE CAST( @clientTimeStamp AS DATETIME2) END, + @level, + @message, + @stacktrace, + CASE WHEN @userId = '' THEN NULL ELSE convert(uniqueidentifier, @userId) END, + @uri, + @server, + CASE WHEN @corrolationId = '' THEN NULL ELSE convert(uniqueidentifier, @corrolationId) END, + @status, + @source)" + + }; + targetDatabase.Parameters.Add(new DatabaseParameterInfo("@serverTimeStamp", new NLog.Layouts.SimpleLayout("${date:universalTime=true}"))); + targetDatabase.Parameters.Add(new DatabaseParameterInfo("@clientTimeStamp", new NLog.Layouts.SimpleLayout("${mdlc:ClientTimeStamp}"))); + targetDatabase.Parameters.Add(new DatabaseParameterInfo("@level", new NLog.Layouts.SimpleLayout("${CoscineLogLevel}"))); + targetDatabase.Parameters.Add(new DatabaseParameterInfo("@message", new NLog.Layouts.SimpleLayout("${message}"))); + targetDatabase.Parameters.Add(new DatabaseParameterInfo("@stackTrace", new NLog.Layouts.SimpleLayout("${exception:format=message}${exception:format=stackTrace}"))); + targetDatabase.Parameters.Add(new DatabaseParameterInfo("@userId", new NLog.Layouts.SimpleLayout("${mdlc:User}"))); + targetDatabase.Parameters.Add(new DatabaseParameterInfo("@uri", new NLog.Layouts.SimpleLayout("${mdlc:Uri}"))); + targetDatabase.Parameters.Add(new DatabaseParameterInfo("@server", new NLog.Layouts.SimpleLayout("${machinename}"))); + targetDatabase.Parameters.Add(new DatabaseParameterInfo("@corrolationId", new NLog.Layouts.SimpleLayout("${activityid}"))); + targetDatabase.Parameters.Add(new DatabaseParameterInfo("@status", new NLog.Layouts.SimpleLayout("${mdlc:Status}"))); + targetDatabase.Parameters.Add(new DatabaseParameterInfo("@source", new NLog.Layouts.SimpleLayout("${callsite}"))); + targetDatabase.Parameters.Add(new DatabaseParameterInfo("@type", new NLog.Layouts.SimpleLayout("${exception:format=type}"))); + targetDatabase.Parameters.Add(new DatabaseParameterInfo("@innerException", new NLog.Layouts.SimpleLayout("${exception:format=:innerFormat=ShortType,Message,Method:MaxInnerExceptionLevel=1:InnerExceptionSeparator=}"))); + targetDatabase.Parameters.Add(new DatabaseParameterInfo("@additionalInfo", new NLog.Layouts.SimpleLayout("${message}"))); + + var targetConsole = new NLog.Targets.ConsoleTarget + { + Name = "console", + Layout = "${date:universalTime=true}|${mdlc:ClientTimeStamp}|${CoscineLogLevel}|${message}|${mdlc:User}|${mdlc:Uri}|${machinename}|${activityid}|${mdlc:Status}|${callsite}|${exception:format=message}${exception:format=stackTrace}" + }; + + + config.AddTarget("fileLogger", targetFileLogger); + config.AddTarget("databaseLogger", targetDatabase); + config.AddTarget("consoleLogger", targetConsole); + + + var blockAllDebug = new LoggingRule("blockAllDebug"); + blockAllDebug.SetLoggingLevels(LogLevel.Debug, LogLevel.Debug); + blockAllDebug.LoggerNamePattern = "*"; + + var blockAllTrace = new LoggingRule("blockAllTrace"); + blockAllTrace.SetLoggingLevels(LogLevel.Trace, LogLevel.Trace); + blockAllTrace.LoggerNamePattern = "*"; + + var blockAllWarning = new LoggingRule("blockAllWarning"); + blockAllWarning.SetLoggingLevels(LogLevel.Warn, LogLevel.Warn); + blockAllWarning.LoggerNamePattern = "*"; + + var blockAllError = new LoggingRule("blockAllError"); + blockAllError.SetLoggingLevels(LogLevel.Error, LogLevel.Error); + blockAllError.LoggerNamePattern = "*"; + + var blockAllFatal = new LoggingRule("blockAllFatal"); + blockAllFatal.SetLoggingLevels(LogLevel.Fatal, LogLevel.Fatal); + blockAllFatal.LoggerNamePattern = "*"; + + var blockAllInformation = new LoggingRule("blockAllInformation"); + blockAllInformation.SetLoggingLevels(LogLevel.Info, LogLevel.Info); + blockAllInformation.LoggerNamePattern = "*"; + + + var ruleFileLogger = new LoggingRule("*", LogLevel.Error, LogLevel.Fatal, targetFileLogger); + var ruleConsole = new LoggingRule("*", LogLevel.Error, LogLevel.Fatal, targetConsole); + var ruleDatabase = new LoggingRule("*", LogLevel.Trace, LogLevel.Fatal, targetDatabase); + + config.LoggingRules.Add(blockAllDebug); + config.LoggingRules.Add(blockAllTrace); + config.LoggingRules.Add(blockAllWarning); + config.LoggingRules.Add(blockAllError); + config.LoggingRules.Add(blockAllFatal); + config.LoggingRules.Add(blockAllInformation); + + config.LoggingRules.Add(ruleFileLogger); + config.LoggingRules.Add(ruleConsole); + config.LoggingRules.Add(ruleDatabase); + + LogManager.Configuration = config; + + UpdateActiveLogs(); + } + + + public void Log() + { + Log(defaultLogType, null, null, null); + } + + public void Log(string message) + { + Log(defaultLogType, null, message, null); + } + + public void Log(Exception exception) + { + Log(defaultLogType, null, null, exception); + } + + public void Log(string message, Exception exception) + { + Log(defaultLogType, null, message, exception); + } + + public void Log(Type context) + { + Log(defaultLogType, context, null, null); + } + + public void Log(Type context, string message) + { + Log(defaultLogType, context, message, null); + } + + public void Log(Type context, Exception exception) + { + Log(defaultLogType, context, null, exception); + } + + public void Log(Type context, string message, Exception exception) + { + Log(defaultLogType, context, message, exception); + } + + public void Log(LogType messageType) + { + Log(messageType, null, null, null); + } + + public void Log(LogType messageType, Type context) + { + Log(messageType, context, null, null); + } + + public void Log(LogType messageType, string message) + { + Log(messageType, null, message, null); + } + + public void Log(LogType messageType, Exception exception) + { + Log(messageType, null, null, exception); + } + + public void Log(LogType messageType, Type context, string message) + { + Log(messageType, context, message, null); + } + + public void Log(LogType messageType, Type context, Exception exception) + { + Log(messageType, context, null, exception); + } + + public void Log(LogType messageType, string message, Exception exception) + { + Log(messageType, null, message, exception); + } + + public void Log(LogType messageType, Type context, string message, Exception exception) + { + UpdateActiveLogs(); + + if (!activeLoglevels[(int)messageType]) + { + return; + } + + Microsoft.Extensions.Logging.LogLevel logLevel; + + switch (messageType) + { + case LogType.Debug: + logLevel = Microsoft.Extensions.Logging.LogLevel.Debug; + break; + case LogType.Low: + logLevel = Microsoft.Extensions.Logging.LogLevel.Trace; + break; + case LogType.Medium: + logLevel = Microsoft.Extensions.Logging.LogLevel.Warning; + break; + case LogType.High: + logLevel = Microsoft.Extensions.Logging.LogLevel.Error; + break; + case LogType.Critical: + logLevel = Microsoft.Extensions.Logging.LogLevel.Critical; + break; + case LogType.Analytics: + SetAnalytics(true); + logLevel = Microsoft.Extensions.Logging.LogLevel.Information; + break; + case LogType.Reporting: + SetReporting(true); + logLevel = Microsoft.Extensions.Logging.LogLevel.Information; + break; + default: + messageType = LogType.Low; + logLevel = Microsoft.Extensions.Logging.LogLevel.Trace; + break; + } + + _logger.Log(logLevel, exception, message); + + } + + + public static void SetUserId(string userId = "00000000-0000-0000-0000-000000000000") + { + if (IsGuid(userId)) + { + MappedDiagnosticsLogicalContext.Set("User", userId); + } + else + { + MappedDiagnosticsLogicalContext.Set("User", ""); + } + } + + public static void SetUserId(Guid userId) + { + CoscineLogger.SetUserId(userId.ToString()); + } + + public static void SetAnalytics(bool active) + { + var value = active ? "true" : "false"; + MappedDiagnosticsLogicalContext.Set("Analytics", value); + } + + public static void SetReporting(bool active) + { + var value = active ? "true" : "false"; + MappedDiagnosticsLogicalContext.Set("Reporting", value); + } + + public static void SetUri(string uri = "") + { + MappedDiagnosticsLogicalContext.Set("Uri", uri); + } + + public static void SetCorrolationId(string corrolationId = "00000000-0000-0000-0000-000000000000") + { + if (IsGuid(corrolationId)) + { + Trace.CorrelationManager.ActivityId = new Guid(corrolationId); + } + else + { + Trace.CorrelationManager.ActivityId = new Guid("00000000-0000-0000-0000-000000000000"); + } + } + + public static void SetCorrolationId() + { + Trace.CorrelationManager.ActivityId = Guid.NewGuid(); + } + + public static void SetCorrolationId(Guid corrolationId) + { + CoscineLogger.SetCorrolationId(corrolationId.ToString()); + } + + public static void SetStatus(string status = "") + { + MappedDiagnosticsLogicalContext.Set("Status", status); + } + + public static void SetClientTimeStamp(string clientTimeStamp = "") + { + MappedDiagnosticsLogicalContext.Set("ClientTimeStamp", clientTimeStamp); + } + + private static bool IsGuid(string guid) + { + var match = Regex.Match(guid, @"^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$", + RegexOptions.IgnoreCase); + return match.Success; + } + + private static void UpdateActiveLogs() + { + activeLoglevels[(int)LogType.Debug] = !GetStringFromConsul(LogLevelKeyDebug).Equals("0"); + activeLoglevels[(int)LogType.Low] = !GetStringFromConsul(LogLevelKeyLow).Equals("0"); + activeLoglevels[(int)LogType.Medium] = !GetStringFromConsul(LogLevelKeyMedium).Equals("0"); + activeLoglevels[(int)LogType.High] = !GetStringFromConsul(LogLevelKeyHigh).Equals("0"); + activeLoglevels[(int)LogType.Critical] = !GetStringFromConsul(LogLevelKeyCritical).Equals("0"); + activeLoglevels[(int)LogType.Analytics] = !GetStringFromConsul(LogLevelKeyAnalytics).Equals("0"); + activeLoglevels[(int)LogType.Reporting] = !GetStringFromConsul(LogLevelKeyReporting).Equals("0"); + + var config = LogManager.Configuration; + config.FindRuleByName("blockAllInformation").Final = !activeLoglevels[(int)LogType.Analytics] && !activeLoglevels[(int)LogType.Reporting]; + config.FindRuleByName("blockAllDebug").Final = !activeLoglevels[(int)LogType.Debug]; + config.FindRuleByName("blockAllTrace").Final = !activeLoglevels[(int)LogType.Low]; + config.FindRuleByName("blockAllWarning").Final = !activeLoglevels[(int)LogType.Medium]; + config.FindRuleByName("blockAllError").Final = !activeLoglevels[(int)LogType.High]; + config.FindRuleByName("blockAllFatal").Final = !activeLoglevels[(int)LogType.Critical]; + + LogManager.Configuration = config; + LogManager.ReconfigExistingLoggers(); + } + + + private static string GetDbConnectionString() + { + var dbDataSource = GetStringFromConsul(DbDataSourceKey); + var dbDatabase = GetStringFromConsul(DbNameKey); + var dbUserId = GetStringFromConsul(DbUserIdKey); + var dbPassword = GetStringFromConsul(DbPasswordKey); + return $"Data Source={dbDataSource}; Database={dbDatabase}; User Id={dbUserId}; Password={dbPassword};"; + } + + private static string GetStringFromConsul(string key) + { + using (var client = new ConsulClient()) + { + var getPair = client.KV.Get(key); + + getPair.Wait(); + + var returnValue = getPair.Result.Response.Value; + + if (returnValue != null) + { + return Encoding.UTF8.GetString(returnValue, 0, returnValue.Length); + } + return null; + + } + } + } +} diff --git a/src/Logging/LogLevelLayoutRenderer.cs b/src/Logging/LogLevelLayoutRenderer.cs new file mode 100644 index 0000000000000000000000000000000000000000..dc42b8e329c03a04948791c261604a388b8779fd --- /dev/null +++ b/src/Logging/LogLevelLayoutRenderer.cs @@ -0,0 +1,60 @@ +using NLog; +using NLog.LayoutRenderers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Coscine.Logging +{ + [LayoutRenderer("CoscineLogLevel")] + class LogLevelLayoutRenderer : LayoutRenderer + { + + protected override void Append(StringBuilder builder, LogEventInfo logEvent) + { + + string levelName; + if (logEvent.Level == LogLevel.Info) + { + if (MappedDiagnosticsLogicalContext.Get("Analytics").Equals("true")) + { + MappedDiagnosticsLogicalContext.Set("Analytics", false); + levelName = "Analytics"; + } + else if (MappedDiagnosticsLogicalContext.Get("Reporting").Equals("true")) + { + MappedDiagnosticsLogicalContext.Set("Reporting", false); + levelName = "Reporting"; + } + else + { + levelName = "Info"; + } + + } + else if (logEvent.Level == LogLevel.Debug) + { + levelName = "Debug"; + } + else if (logEvent.Level == LogLevel.Warn) + { + levelName = "Medium"; + } + else if (logEvent.Level == LogLevel.Error) + { + levelName = "High"; + } + else if (logEvent.Level == LogLevel.Fatal) + { + levelName = "Critical"; + } + else + { + levelName = "Low"; + } + builder.Append(levelName); + } + } +} diff --git a/src/Logging/LogType.cs b/src/Logging/LogType.cs new file mode 100644 index 0000000000000000000000000000000000000000..4d178218c7c422b941fca22864d499fd651cb3cd --- /dev/null +++ b/src/Logging/LogType.cs @@ -0,0 +1,14 @@ +namespace Coscine.Logging +{ + + public enum LogType + { + Debug = 0, + Low = 1, + Medium = 2, + High = 3, + Critical = 4, + Analytics = 5, + Reporting = 6 + } +} diff --git a/src/Logging/Logging.csproj b/src/Logging/Logging.csproj new file mode 100644 index 0000000000000000000000000000000000000000..5941eb7aacf846fad892533c69083c29d07f00aa --- /dev/null +++ b/src/Logging/Logging.csproj @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{C7025063-054B-4E19-81DC-353DF49ADB3A}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>Coscine.Logging</RootNamespace> + <AssemblyName>Coscine.Logging</AssemblyName> + <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <Deterministic>true</Deterministic> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup> + <SignAssembly>true</SignAssembly> + </PropertyGroup> + <PropertyGroup> + <AssemblyOriginatorKeyFile>Coscine.Logging.snk</AssemblyOriginatorKeyFile> + </PropertyGroup> + <ItemGroup> + <Reference Include="Consul, Version=0.7.2.6, Culture=neutral, PublicKeyToken=20a6ad9a81df1d95, processorArchitecture=MSIL"> + <HintPath>..\packages\Consul.0.7.2.6\lib\net45\Consul.dll</HintPath> + </Reference> + <Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL"> + <HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath> + </Reference> + <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL"> + <HintPath>..\packages\NLog.4.6.8\lib\net45\NLog.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.ComponentModel.DataAnnotations" /> + <Reference Include="System.Configuration" /> + <Reference Include="System.Core" /> + <Reference Include="System.IO.Compression" /> + <Reference Include="System.Net.Http.WebRequest" /> + <Reference Include="System.Numerics" /> + <Reference Include="System.Runtime.Serialization" /> + <Reference Include="System.ServiceModel" /> + <Reference Include="System.Transactions" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Net.Http" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="CoscineLogger.cs" /> + <Compile Include="LogLevelLayoutRenderer.cs" /> + <Compile Include="LogType.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <None Include="App.config" /> + <None Include="Coscine.Logging.snk" /> + <None Include="packages.config" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> +</Project> \ No newline at end of file diff --git a/src/Logging/Logging.nuspec b/src/Logging/Logging.nuspec new file mode 100644 index 0000000000000000000000000000000000000000..986eb657905d2c27d77301d6bd6aafc5a8d957ce --- /dev/null +++ b/src/Logging/Logging.nuspec @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<package > + <metadata> + <id>$id$</id> + <version>$version$</version> + <title>$title$</title> + <authors>rwth-aachen</authors> + <owners>rwth-aachen</owners> + <license type="expression">MIT</license> + <projectUrl>https://git.rwth-aachen.de/coscine/cs/logging</projectUrl> + <requireLicenseAcceptance>false</requireLicenseAcceptance> + <description>$description$</description> + <copyright>$copyright$</copyright> + </metadata> +</package> \ No newline at end of file diff --git a/src/Logging/Properties/AssemblyInfo.cs b/src/Logging/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000000000000000000000000000000000..9435608867d358fd3b54b3325884bea7f3b36f87 --- /dev/null +++ b/src/Logging/Properties/AssemblyInfo.cs @@ -0,0 +1,11 @@ +using System.Reflection; + +[assembly: AssemblyTitle("Logging")] +[assembly: AssemblyDescription("Logging is a part of the CoScInE group.")] +[assembly: AssemblyCompany("IT Center, RWTH Aachen University")] +[assembly: AssemblyProduct("Logging")] +[assembly: AssemblyVersion("0.0.1.0")] +[assembly: AssemblyFileVersion("0.0.1.0")] +[assembly: AssemblyInformationalVersion("0.0.1.0")] +[assembly: AssemblyCopyright("2019 IT Center, RWTH Aachen University")] + diff --git a/src/Logging/packages.config b/src/Logging/packages.config new file mode 100644 index 0000000000000000000000000000000000000000..7fcf9f86bdc44872105c6d6c41cde1171fb0f661 --- /dev/null +++ b/src/Logging/packages.config @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="Consul" version="0.7.2.6" targetFramework="net472" /> + <package id="Microsoft.Extensions.Logging.Abstractions" version="2.2.0" targetFramework="net461" /> + <package id="NLog" version="4.6.8" targetFramework="net472" /> + <package id="NLog.Config" version="4.6.8" targetFramework="net472" /> + <package id="NLog.Schema" version="4.6.8" targetFramework="net472" /> +</packages> \ No newline at end of file