Merge branch 'temp8' into temp8-ui-cleanup

This commit is contained in:
Mads Rasmussen
2018-08-29 09:54:20 +02:00
300 changed files with 3894 additions and 3937 deletions

View File

@@ -33,8 +33,6 @@
<dependency id="LightInject.Annotation" version="[1.1.0,1.999999)" />
<dependency id="LightInject.Mvc" version="[2.0.0,2.999999)" />
<dependency id="LightInject.WebApi" version="[2.0.0,2.999999)" />
<dependency id="log4net" version="[2.0.8,2.999999)" />
<dependency id="Log4Net.Async" version="[2.0.4,2.999999)" />
<dependency id="Lucene.Net.Contrib" version="[3.0.3,3.999999)" />
<dependency id="Markdown" version="[2.2.1,2.999999)" />
<dependency id="Microsoft.AspNet.Identity.Owin" version="[2.2.1,2.999999)" />
@@ -53,6 +51,13 @@
<dependency id="Newtonsoft.Json" version="[11.0.2,11.999999)" />
<dependency id="NPoco" version="[3.9.3,3.999999)" />
<dependency id="Semver" version="[2.0.4,2.999999)" />
<dependency id="Serilog" version="[2.7.1,2.999999)" />
<dependency id="Serilog.Enrichers.Process" version="[2.0.1,2.999999)" />
<dependency id="Serilog.Enrichers.Thread" version="[3.0.0,3.999999)" />
<dependency id="Serilog.Filters.Expressions" version="[2.0.0,2.999999)" />
<dependency id="Serilog.Formatting.Compact" version="[1.0.0,1.999999)" />
<dependency id="Serilog.Settings.AppSettings" version="[2.1.2,2.999999)" />
<dependency id="Serilog.Sinks.File" version="[4.0.0,4.999999)" />
<dependency id="System.Reflection.Primitives" version="[4.3.0,4.999999)" />
<dependency id="System.Runtime.Handles" version="[4.3.0,4.999999)" />
<dependency id="System.Security.Cryptography.X509Certificates" version="[4.3.2,4.999999)" />

View File

@@ -22,7 +22,7 @@
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.3, 2.999999)" />
<dependency id="Umbraco.ModelsBuilder.Ui" version="[8.0.0-alpha.20]" />
<dependency id="Umbraco.ModelsBuilder.Ui" version="[8.0.0-alpha.22]" />
</dependencies>
</metadata>
<files>
@@ -35,7 +35,6 @@
<file src="$BuildTmp$\WebApp\config\splashes\**" target="UmbracoFiles\Config\splashes" />
<file src="$BuildTmp$\WebApp\config\BackOfficeTours\**" target="Content\Config\BackOfficeTours" />
<file src="$BuildTmp$\WebApp\umbraco\**" target="UmbracoFiles\umbraco" />
<file src="$BuildTmp$\WebApp\umbraco_client\**" target="UmbracoFiles\umbraco_client" />
<file src="$BuildTmp$\WebApp\Media\Web.config" target="Content\Media\Web.config" />
<file src="$BuildTmp$\WebApp\App_Plugins\ModelsBuilder\modelsbuilder.htm" target="Content\App_Plugins\ModelsBuilder\modelsbuilder.htm" />

View File

@@ -33,7 +33,6 @@ if ($project) {
robocopy $umbracoBinFolder $umbracoBinBackupPath /e /LOG:$copyLogsPath\UmbracoBinBackup.log
# Delete files Umbraco ships with
if(Test-Path $umbracoBinFolder\log4net.dll) { Remove-Item $umbracoBinFolder\log4net.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.ApplicationBlocks.Data.dll) { Remove-Item $umbracoBinFolder\Microsoft.ApplicationBlocks.Data.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Data.SqlServerCe.dll) { Remove-Item $umbracoBinFolder\System.Data.SqlServerCe.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Data.SqlServerCe.Entity.dll) { Remove-Item $umbracoBinFolder\System.Data.SqlServerCe.Entity.dll -Force -Confirm:$false }

View File

@@ -19,4 +19,4 @@ using System.Resources;
// these are FYI and changed automatically
[assembly: AssemblyFileVersion("8.0.0")]
[assembly: AssemblyInformationalVersion("8.0.0-alpha.44")]
[assembly: AssemblyInformationalVersion("8.0.0-alpha.49")]

View File

@@ -18,10 +18,7 @@ namespace Umbraco.Core
// this only gets called when an assembly can't be resolved
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
private static readonly Regex Log4NetAssemblyPattern = new Regex("log4net, Version=([\\d\\.]+?), Culture=neutral, PublicKeyToken=\\w+$", RegexOptions.Compiled);
private const string Log4NetReplacement = "log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a";
/// <summary>
/// This is used to do an assembly binding redirect via code - normally required due to signature changes in assemblies
/// </summary>
@@ -30,12 +27,6 @@ namespace Umbraco.Core
/// <returns></returns>
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
//log4net:
if (Log4NetAssemblyPattern.IsMatch(args.Name) && args.Name != Log4NetReplacement)
{
return Assembly.Load(Log4NetAssemblyPattern.Replace(args.Name, Log4NetReplacement));
}
//AutoMapper:
// ensure the assembly is indeed AutoMapper and that the PublicKeyToken is null before trying to Load again
// do NOT just replace this with 'return Assembly', as it will cause an infinite loop -> stackoverflow

View File

@@ -111,15 +111,15 @@ namespace Umbraco.Core.Components
catch (Exception e)
{
// in case of an error, force-dump everything to log
_logger.Info<BootLoader>(() => GetComponentsReport(requirements));
_logger.Error<BootLoader>("Failed to sort components.", e);
_logger.Info<BootLoader>("Component Report:\r\n{ComponentReport}", GetComponentsReport(requirements));
_logger.Error<BootLoader>(e, "Failed to sort compontents.");
throw;
}
// bit verbose but should help for troubleshooting
var text = "Ordered Components: " + Environment.NewLine + string.Join(Environment.NewLine, sortedComponentTypes) + Environment.NewLine;
Console.WriteLine(text);
_logger.Debug<BootLoader>(text);
_logger.Debug<BootLoader>("Ordered Components: {SortedComponentTypes}", sortedComponentTypes);
return sortedComponentTypes;
}

View File

@@ -148,7 +148,7 @@ namespace Umbraco.Core.Composing
catch (FileNotFoundException ex)
{
//this will occur if it cannot load the assembly
Current.Logger.Error(typeof(TypeFinder), "Could not load assembly App_Code", ex);
Current.Logger.Error(typeof(TypeFinder), ex, "Could not load assembly App_Code");
}
}
}
@@ -224,7 +224,6 @@ namespace Umbraco.Core.Composing
"Dynamic,",
"HtmlDiff,",
"Iesi.Collections,",
"log4net,",
"Microsoft.",
"Newtonsoft.",
"NHibernate.",
@@ -440,7 +439,7 @@ namespace Umbraco.Core.Composing
}
catch (TypeLoadException ex)
{
Current.Logger.Error(typeof(TypeFinder), $"Could not query types on {assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", ex);
Current.Logger.Error(typeof(TypeFinder), ex, "Could not query types on {Assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly);
continue;
}
@@ -506,7 +505,7 @@ namespace Umbraco.Core.Composing
}
catch (TypeLoadException ex)
{
Current.Logger.Error(typeof(TypeFinder), $"Could not query types on {assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", ex);
Current.Logger.Error(typeof(TypeFinder), ex, "Could not query types on {Assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly);
continue;
}
@@ -573,7 +572,7 @@ namespace Umbraco.Core.Composing
if (NotifiedLoadExceptionAssemblies.Contains(a.FullName) == false)
{
NotifiedLoadExceptionAssemblies.Add(a.FullName);
Current.Logger.Warn(typeof (TypeFinder), ex, $"Could not load all types from {a.GetName().Name}.");
Current.Logger.Warn(typeof (TypeFinder), ex, "Could not load all types from {TypeName}.", a.GetName().Name);
}
}
return rex.Types.WhereNotNull().ToArray();

View File

@@ -494,7 +494,7 @@ namespace Umbraco.Core.Composing
if (--attempts == 0)
throw;
_logger.Logger.Debug<TypeLoader>(() => $"Attempted to get filestream for file {path} failed, {attempts} attempts left, pausing for {pauseMilliseconds} milliseconds");
_logger.Logger.Debug<TypeLoader>("Attempted to get filestream for file {Path} failed, {NumberOfAttempts} attempts left, pausing for {PauseMilliseconds} milliseconds", path, attempts, pauseMilliseconds);
Thread.Sleep(pauseMilliseconds);
}
}
@@ -645,7 +645,7 @@ namespace Umbraco.Core.Composing
if (typeList != null)
{
// need to put some logging here to try to figure out why this is happening: http://issues.umbraco.org/issue/U4-3505
_logger.Logger.Debug<TypeLoader>(() => $"Getting {GetName(baseType, attributeType)}: found a cached type list.");
_logger.Logger.Debug<TypeLoader>("Getting {TypeName}: found a cached type list.", GetName(baseType, attributeType));
return typeList.Types;
}
@@ -676,7 +676,7 @@ namespace Umbraco.Core.Composing
// so in this instance there will never be a result.
if (cacheResult.Exception is CachedTypeNotFoundInFileException || cacheResult.Success == false)
{
_logger.Logger.Debug<TypeLoader>(() => $"Getting {GetName(baseType, attributeType)}: failed to load from cache file, must scan assemblies.");
_logger.Logger.Debug<TypeLoader>("Getting {TypeName}: failed to load from cache file, must scan assemblies.", GetName(baseType, attributeType));
scan = true;
}
else
@@ -695,7 +695,7 @@ namespace Umbraco.Core.Composing
catch (Exception ex)
{
// in case of any exception, we have to exit, and revert to scanning
_logger.Logger.Error<TypeLoader>("Getting " + GetName(baseType, attributeType) + ": failed to load cache file type " + type + ", reverting to scanning assemblies.", ex);
_logger.Logger.Error<TypeLoader>(ex, "Getting {TypeName}: failed to load cache file type {CacheType}, reverting to scanning assemblies.", GetName(baseType, attributeType), type);
scan = true;
break;
}
@@ -703,7 +703,7 @@ namespace Umbraco.Core.Composing
if (scan == false)
{
_logger.Logger.Debug<TypeLoader>(() => $"Getting {GetName(baseType, attributeType)}: loaded types from cache file.");
_logger.Logger.Debug<TypeLoader>("Getting {TypeName}: loaded types from cache file.", GetName(baseType, attributeType));
}
}
}
@@ -711,7 +711,7 @@ namespace Umbraco.Core.Composing
if (scan)
{
// either we had to scan, or we could not get the types from the cache file - scan now
_logger.Logger.Debug<TypeLoader>(() => $"Getting {GetName(baseType, attributeType)}: scanning assemblies.");
_logger.Logger.Debug<TypeLoader>("Getting {TypeName}: scanning assemblies.", GetName(baseType, attributeType));
foreach (var t in finder())
typeList.Add(t);
@@ -729,11 +729,11 @@ namespace Umbraco.Core.Composing
UpdateCache();
}
_logger.Logger.Debug<TypeLoader>(() => $"Got {GetName(baseType, attributeType)}, caching ({added.ToString().ToLowerInvariant()}).");
_logger.Logger.Debug<TypeLoader>("Got {TypeName}, caching ({CacheType}).", GetName(baseType, attributeType), added.ToString().ToLowerInvariant());
}
else
{
_logger.Logger.Debug<TypeLoader>(() => $"Got {GetName(baseType, attributeType)}.");
_logger.Logger.Debug<TypeLoader>("Got {TypeName}.", GetName(baseType, attributeType));
}
return typeList.Types;

View File

@@ -79,13 +79,13 @@ namespace Umbraco.Core.Configuration
versionAttribute.SetValue(newVersion);
clientDependencyConfigXml.Save(_fileName, SaveOptions.DisableFormatting);
_logger.Info<ClientDependencyConfiguration>(() => $"Updated version number from {oldVersion} to {newVersion}");
_logger.Info<ClientDependencyConfiguration>("Updated version number from {OldVersion} to {NewVersion}", oldVersion, newVersion);
return true;
}
}
catch (Exception ex)
{
_logger.Error<ClientDependencyConfiguration>("Couldn't update ClientDependency version number", ex);
_logger.Error<ClientDependencyConfiguration>(ex, "Couldn't update ClientDependency version number");
}
return false;
@@ -113,13 +113,13 @@ namespace Umbraco.Core.Configuration
versionAttribute.SetValue(newVersion);
clientDependencyConfigXml.Save(_fileName, SaveOptions.DisableFormatting);
_logger.Info<ClientDependencyConfiguration>(() => $"Updated version number from {oldVersion} to {newVersion}");
_logger.Info<ClientDependencyConfiguration>("Updated version number from {OldVersion} to {NewVersion}", oldVersion, newVersion);
return true;
}
}
catch (Exception ex)
{
_logger.Error<ClientDependencyConfiguration>("Couldn't update ClientDependency version number", ex);
_logger.Error<ClientDependencyConfiguration>(ex, "Couldn't update ClientDependency version number");
}
return false;
@@ -150,7 +150,7 @@ namespace Umbraco.Core.Configuration
catch (Exception ex)
{
//invalid path format or something... try/catch to be safe
_logger.Error<ClientDependencyConfiguration>("Could not get path from ClientDependency.config", ex);
_logger.Error<ClientDependencyConfiguration>(ex, "Could not get path from ClientDependency.config");
}
var success = true;
@@ -167,7 +167,7 @@ namespace Umbraco.Core.Configuration
catch (Exception ex)
{
// Something could be locking the directory or the was another error, making sure we don't break the upgrade installer
_logger.Error<ClientDependencyConfiguration>("Could not clear temp files", ex);
_logger.Error<ClientDependencyConfiguration>(ex, "Could not clear temp files");
success = false;
}
}

View File

@@ -40,13 +40,15 @@ namespace Umbraco.Core.Configuration.Grid
var gridConfig = Path.Combine(_configFolder.FullName, "grid.editors.config.js");
if (File.Exists(gridConfig))
{
var sourceString = File.ReadAllText(gridConfig);
try
{
editors.AddRange(parser.ParseGridEditors(File.ReadAllText(gridConfig)));
editors.AddRange(parser.ParseGridEditors(sourceString));
}
catch (Exception ex)
{
_logger.Error<GridEditorsConfig>("Could not parse the contents of grid.editors.config.js into a JSON array", ex);
_logger.Error<GridEditorsConfig>(ex, "Could not parse the contents of grid.editors.config.js into a JSON array '{Json}", sourceString);
}
}

View File

@@ -88,7 +88,7 @@ namespace Umbraco.Core.Configuration
if (_healthChecks == null)
{
var ex = new ConfigurationErrorsException("Could not load the " + typeof(IHealthChecks) + " from config file, ensure the web.config and healthchecks.config files are formatted correctly");
Current.Logger.Error<UmbracoConfig>("Config error", ex);
Current.Logger.Error<UmbracoConfig>(ex, "Config error");
throw ex;
}
@@ -103,7 +103,7 @@ namespace Umbraco.Core.Configuration
if (_dashboardSection == null)
{
var ex = new ConfigurationErrorsException("Could not load the " + typeof(IDashboardSection) + " from config file, ensure the web.config and Dashboard.config files are formatted correctly");
Current.Logger.Error<UmbracoConfig>("Config error", ex);
Current.Logger.Error<UmbracoConfig>(ex, "Config error");
throw ex;
}
@@ -162,7 +162,7 @@ namespace Umbraco.Core.Configuration
if (_umbracoSettings == null)
{
var ex = new ConfigurationErrorsException("Could not load the " + typeof (IUmbracoSettingsSection) + " from config file, ensure the web.config and umbracoSettings.config files are formatted correctly");
Current.Logger.Error<UmbracoConfig>("Config error", ex);
Current.Logger.Error<UmbracoConfig>(ex, "Config error");
throw ex;
}

View File

@@ -22,7 +22,7 @@ namespace Umbraco.Core.Configuration
/// <summary>
/// Gets the version comment of the executing code (eg "beta").
/// </summary>
public static string CurrentComment => "alpha.44";
public static string CurrentComment => "alpha.49";
/// <summary>
/// Gets the assembly version of Umbraco.Code.dll.

View File

@@ -111,7 +111,7 @@ namespace Umbraco.Core.IO
}
catch (Exception e)
{
Logger.Error<MediaFileSystem>("Failed to delete attached file \"" + file + "\".", e);
Logger.Error<MediaFileSystem>(e, "Failed to delete attached file '{File}'", file);
}
});
}

View File

@@ -73,11 +73,11 @@ namespace Umbraco.Core.IO
}
catch (UnauthorizedAccessException ex)
{
Current.Logger.Error<PhysicalFileSystem>("Not authorized to get directories", ex);
Current.Logger.Error<PhysicalFileSystem>(ex, "Not authorized to get directories for '{Path}'", fullPath);
}
catch (DirectoryNotFoundException ex)
{
Current.Logger.Error<PhysicalFileSystem>("Directory not found", ex);
Current.Logger.Error<PhysicalFileSystem>(ex, "Directory not found for '{Path}'", fullPath);
}
return Enumerable.Empty<string>();
@@ -109,7 +109,7 @@ namespace Umbraco.Core.IO
}
catch (DirectoryNotFoundException ex)
{
Current.Logger.Error<PhysicalFileSystem>("Directory not found", ex);
Current.Logger.Error<PhysicalFileSystem>(ex, "Directory not found for '{Path}'", fullPath);
}
}
@@ -189,11 +189,11 @@ namespace Umbraco.Core.IO
}
catch (UnauthorizedAccessException ex)
{
Current.Logger.Error<PhysicalFileSystem>("Not authorized to get directories", ex);
Current.Logger.Error<PhysicalFileSystem>(ex, "Not authorized to get directories for '{Path}'", fullPath);
}
catch (DirectoryNotFoundException ex)
{
Current.Logger.Error<PhysicalFileSystem>("Directory not found", ex);
Current.Logger.Error<PhysicalFileSystem>(ex, "Directory not found for '{FullPath}'", fullPath);
}
return Enumerable.Empty<string>();
@@ -226,7 +226,7 @@ namespace Umbraco.Core.IO
}
catch (FileNotFoundException ex)
{
Current.Logger.Info<PhysicalFileSystem>(() => $"DeleteFile failed with FileNotFoundException: {ex.InnerException}");
Current.Logger.Error<PhysicalFileSystem>(ex.InnerException, "DeleteFile failed with FileNotFoundException for '{Path}'", fullPath);
}
}

View File

@@ -54,7 +54,7 @@ namespace Umbraco.Core.IO
}
_logger = logger;
_logger.Debug<ShadowFileSystems>(() => "Shadow " + id + ".");
_logger.Debug<ShadowFileSystems>("Shadow '{ShadowId}'", id);
_id = id;
_wrappers = wrappers;
@@ -112,7 +112,7 @@ namespace Umbraco.Core.IO
{
lock (Locker)
{
_logger.Debug<ShadowFileSystems>(() => "UnShadow " + _id + " (" + (_completed ? "complete" : "abort") + ").");
_logger.Debug<ShadowFileSystems>("UnShadow '{ShadowId}' {Status}", _id, _completed ? "complete" : "abort");
var exceptions = new List<Exception>();
foreach (var wrapper in _wrappers)

View File

@@ -1,21 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace Umbraco.Core.Logging
{
/// <summary>
/// Allows for outputting a normalized appdomainappid token in a log format
/// </summary>
public sealed class AppDomainTokenConverter : log4net.Util.PatternConverter
{
protected override void Convert(TextWriter writer, object state)
{
writer.Write(HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty));
}
}
}

View File

@@ -1,121 +0,0 @@
using log4net.Appender;
using log4net.Core;
using log4net.Util;
using System;
using System.Runtime.Remoting.Messaging;
namespace Umbraco.Core.Logging
{
/// <summary>
/// Borrowed from https://github.com/cjbhaines/Log4Net.Async - will reference Nuget packages directly in v8
/// </summary>
public abstract class AsyncForwardingAppenderBase : ForwardingAppender
{
#region Private Members
private const FixFlags DefaultFixFlags = FixFlags.Partial;
private FixFlags fixFlags = DefaultFixFlags;
private LoggingEventHelper loggingEventHelper;
#endregion Private Members
#region Properties
public FixFlags Fix
{
get { return fixFlags; }
set { SetFixFlags(value); }
}
/// <summary>
/// Returns HttpContext.Current
/// </summary>
protected internal object HttpContext
{
get
{
return CallContext.HostContext;
}
set
{
CallContext.HostContext = value;
}
}
/// <summary>
/// The logger name that will be used for logging internal errors.
/// </summary>
protected abstract string InternalLoggerName { get; }
public abstract int? BufferSize { get; set; }
#endregion Properties
public override void ActivateOptions()
{
base.ActivateOptions();
loggingEventHelper = new LoggingEventHelper(InternalLoggerName, DefaultFixFlags);
InitializeAppenders();
}
#region Appender Management
public override void AddAppender(IAppender newAppender)
{
base.AddAppender(newAppender);
SetAppenderFixFlags(newAppender);
}
private void SetFixFlags(FixFlags newFixFlags)
{
if (newFixFlags != fixFlags)
{
loggingEventHelper.Fix = newFixFlags;
fixFlags = newFixFlags;
InitializeAppenders();
}
}
private void InitializeAppenders()
{
foreach (var appender in Appenders)
{
SetAppenderFixFlags(appender);
}
}
private void SetAppenderFixFlags(IAppender appender)
{
var bufferingAppender = appender as BufferingAppenderSkeleton;
if (bufferingAppender != null)
{
bufferingAppender.Fix = Fix;
}
}
#endregion Appender Management
#region Forwarding
protected void ForwardInternalError(string message, Exception exception, Type thisType)
{
LogLog.Error(thisType, message, exception);
var loggingEvent = loggingEventHelper.CreateLoggingEvent(Level.Error, message, exception);
ForwardLoggingEvent(loggingEvent, thisType);
}
protected void ForwardLoggingEvent(LoggingEvent loggingEvent, Type thisType)
{
try
{
base.Append(loggingEvent);
}
catch (Exception exception)
{
LogLog.Error(thisType, "Unable to forward logging event", exception);
}
}
#endregion Forwarding
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Linq;
namespace Umbraco.Core.Logging
{
@@ -9,95 +8,107 @@ namespace Umbraco.Core.Logging
public class DebugDiagnosticsLogger : ILogger
{
/// <inheritdoc/>
public void Error(Type reporting, string message, Exception exception = null)
public void Fatal(Type reporting, Exception exception, string message)
{
System.Diagnostics.Debug.WriteLine(message + Environment.NewLine + exception, reporting.FullName);
}
/// <inheritdoc/>
public void Fatal(Type reporting, Exception exception)
{
System.Diagnostics.Debug.WriteLine(Environment.NewLine + exception, reporting.FullName);
}
/// <inheritdoc/>
public void Fatal(Type reporting, string message)
{
System.Diagnostics.Debug.WriteLine(message);
}
/// <inheritdoc/>
public void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] args)
{
System.Diagnostics.Debug.WriteLine(string.Format(messageTemplate, args) + Environment.NewLine + exception, reporting.FullName);
}
/// <inheritdoc/>
public void Fatal(Type reporting, string messageTemplate, params object[] args)
{
System.Diagnostics.Debug.WriteLine(messageTemplate, args);
}
/// <inheritdoc/>
public void Error(Type reporting, Exception exception, string message)
{
System.Diagnostics.Debug.WriteLine(message + Environment.NewLine + exception, reporting.FullName);
}
/// <inheritdoc/>
public void Error(Type reporting, Exception exception)
{
System.Diagnostics.Debug.WriteLine(Environment.NewLine + exception, reporting.FullName);
}
/// <inheritdoc/>
public void Error(Type reporting, string message)
{
System.Diagnostics.Debug.WriteLine(message);
}
/// <inheritdoc/>
public void Error(Type reporting, Exception exception, string messageTemplate, params object[] args)
{
System.Diagnostics.Debug.WriteLine(string.Format(messageTemplate, args) + Environment.NewLine + exception, reporting.FullName);
}
/// <inheritdoc/>
public void Error(Type reporting, string messageTemplate, params object[] args)
{
System.Diagnostics.Debug.WriteLine(messageTemplate, args);
}
/// <inheritdoc/>
public void Warn(Type reporting, string format)
{
System.Diagnostics.Debug.WriteLine(format, reporting.FullName);
}
/// <inheritdoc/>
public void Warn(Type reporting, Func<string> messageBuilder)
{
System.Diagnostics.Debug.WriteLine(messageBuilder(), reporting.FullName);
}
/// <inheritdoc/>
public void Warn(Type reporting, string format, params object[] args)
{
System.Diagnostics.Debug.WriteLine(string.Format(format, args), reporting.FullName);
}
/// <inheritdoc/>
public void Warn(Type reporting, string format, params Func<object>[] args)
{
System.Diagnostics.Debug.WriteLine(string.Format(format, args.Select(x => x()).ToArray()), reporting.FullName);
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, string message)
{
System.Diagnostics.Debug.WriteLine(message + Environment.NewLine + exception, reporting.FullName);
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, Func<string> messageBuilder)
{
System.Diagnostics.Debug.WriteLine(messageBuilder() + Environment.NewLine + exception, reporting.FullName);
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, string format, params object[] args)
{
System.Diagnostics.Debug.WriteLine(string.Format(format + Environment.NewLine + exception, args), reporting.FullName);
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, string format, params Func<object>[] args)
{
System.Diagnostics.Debug.WriteLine(string.Format(format + Environment.NewLine + exception, args.Select(x => x()).ToArray()), reporting.FullName);
}
/// <inheritdoc/>
public void Info(Type reporting, string message)
{
System.Diagnostics.Debug.WriteLine(message, reporting.FullName);
}
/// <inheritdoc/>
public void Info(Type reporting, Func<string> messageBuilder)
{
System.Diagnostics.Debug.WriteLine(messageBuilder(), reporting.FullName);
}
/// <inheritdoc/>
public void Info(Type reporting, string format, params object[] args)
{
System.Diagnostics.Debug.WriteLine(string.Format(format, args), reporting.FullName);
}
/// <inheritdoc/>
public void Info(Type reporting, string format, params Func<object>[] args)
{
System.Diagnostics.Debug.WriteLine(string.Format(format, args.Select(x => x()).ToArray()), reporting.FullName);
}
/// <inheritdoc/>
public void Debug(Type reporting, string message)
{
System.Diagnostics.Debug.WriteLine(message, reporting.FullName);
}
/// <inheritdoc/>
public void Debug(Type reporting, Func<string> messageBuilder)
{
System.Diagnostics.Debug.WriteLine(messageBuilder(), reporting.FullName);
}
/// <inheritdoc/>
public void Debug(Type reporting, string format, params object[] args)
{
@@ -105,9 +116,16 @@ namespace Umbraco.Core.Logging
}
/// <inheritdoc/>
public void Debug(Type reporting, string format, params Func<object>[] args)
public void Verbose(Type reporting, string message)
{
System.Diagnostics.Debug.WriteLine(string.Format(format, args.Select(x => x()).ToArray()), reporting.FullName);
System.Diagnostics.Debug.WriteLine(message, reporting.FullName);
}
/// <inheritdoc/>
public void Verbose(Type reporting, string format, params object[] args)
{
System.Diagnostics.Debug.WriteLine(string.Format(format, args), reporting.FullName);
}
}
}

View File

@@ -1,8 +1,7 @@
using System;
using System.Diagnostics;
using Umbraco.Core.Logging;
namespace Umbraco.Core
namespace Umbraco.Core.Logging
{
/// <summary>
/// Starts the timer and invokes a callback upon disposal. Provides a simple way of timing an operation by wrapping it in a <code>using</code> (C#) statement.
@@ -18,6 +17,7 @@ namespace Umbraco.Core
private string _failMessage;
private Exception _failException;
private bool _failed;
private readonly string _timingId;
internal enum LogType
{
@@ -38,16 +38,17 @@ namespace Umbraco.Core
_endMessage = endMessage;
_failMessage = failMessage;
_thresholdMilliseconds = thresholdMilliseconds < 0 ? 0 : thresholdMilliseconds;
_timingId = Guid.NewGuid().ToString("N");
if (thresholdMilliseconds == 0)
{
switch (logType)
{
case LogType.Debug:
logger.Debug(loggerType, startMessage);
logger.Debug(loggerType, "[Timing {TimingId}] {StartMessage}", _timingId, startMessage);
break;
case LogType.Info:
logger.Info(loggerType, startMessage);
logger.Info(loggerType, "[Timing {TimingId}] {StartMessage}", _timingId, startMessage);
break;
default:
throw new ArgumentOutOfRangeException(nameof(logType));
@@ -91,15 +92,15 @@ namespace Umbraco.Core
{
if (_failed)
{
_logger.Error(_loggerType, $"{_failMessage} ({Stopwatch.ElapsedMilliseconds}ms)", _failException);
_logger.Error(_loggerType, _failException, "[Timing {TimingId}] {FailMessage} ({TimingDuration}ms)", _timingId, _failMessage, Stopwatch.ElapsedMilliseconds);
}
else switch (_logType)
{
case LogType.Debug:
_logger.Debug(_loggerType, () => $"{_endMessage} ({Stopwatch.ElapsedMilliseconds}ms)");
_logger.Debug(_loggerType, "[Timing {TimingId}] {EndMessage} ({TimingDuration}ms)", _timingId, _endMessage, Stopwatch.ElapsedMilliseconds);
break;
case LogType.Info:
_logger.Info(_loggerType, () => $"{_endMessage} ({Stopwatch.ElapsedMilliseconds}ms)");
_logger.Info(_loggerType, "[Timing {TimingId}] {EndMessage} ({TimingDuration}ms)", _timingId, _endMessage, Stopwatch.ElapsedMilliseconds);
break;
// filtered in the ctor
//default:

View File

@@ -1,22 +1,98 @@
using System;
using System.ComponentModel;
namespace Umbraco.Core.Logging
{
/// <summary>
/// Defines the logging service.
/// </summary>
/// <remarks>
/// <para>Message templates in logging methods follow the Message Templates specification
/// available at https://messagetemplates.org/ in order to support structured logging.</para>
/// <para>Implementations must ensure that they support these templates. Note that the
/// specification includes support for traditional C# numeric placeholders.</para>
/// <para>For instance, "Processed {Input} in {Time}ms."</para>
/// </remarks>
public interface ILogger
{
/// <summary>
/// Logs a fatal message with an exception.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="exception">An exception.</param>
/// <param name="message">A message.</param>
void Fatal(Type reporting, Exception exception, string message);
/// <summary>
/// Logs a fatal exception.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="exception">An exception.</param>
/// <remarks>The message string is unspecified and is implementation-specific.</remarks>
void Fatal(Type reporting, Exception exception);
/// <summary>
/// Logs a fatal message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="message">A message.</param>
void Fatal(Type reporting, string message);
/// <summary>
/// Logs a fatal message with an exception.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="exception">An exception.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues);
/// <summary>
/// Logs a fatal message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Fatal(Type reporting, string messageTemplate, params object[] propertyValues);
/// <summary>
/// Logs an error message with an exception.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="exception">An exception.</param>
/// <param name="message">A message.</param>
void Error(Type reporting, Exception exception, string message);
/// <summary>
/// Logs an error exception.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="exception">An exception.</param>
/// <remarks>The message string is unspecified and is implementation-specific.</remarks>
void Error(Type reporting, Exception exception);
/// <summary>
/// Logs an error message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="message">A message.</param>
/// <param name="exception">An exception.</param>
void Error(Type reporting, string message, Exception exception = null);
void Error(Type reporting, string message);
// note: should we have more overloads for Error too?
/// <summary>
/// Logs an error message with an exception.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="exception">An exception.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Error(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues);
/// <summary>
/// Logs an error message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Error(Type reporting, string messageTemplate, params object[] propertyValues);
/// <summary>
/// Logs a warning message.
@@ -29,8 +105,9 @@ namespace Umbraco.Core.Logging
/// Logs a warning message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="messageBuilder">A message builder.</param>
void Warn(Type reporting, Func<string> messageBuilder);
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Warn(Type reporting, string messageTemplate, params object[] propertyValues);
/// <summary>
/// Logs a warning message with an exception.
@@ -45,8 +122,9 @@ namespace Umbraco.Core.Logging
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="exception">An exception.</param>
/// <param name="messageBuilder">A message builder.</param>
void Warn(Type reporting, Exception exception, Func<string> messageBuilder);
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Warn(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues);
/// <summary>
/// Logs an information message.
@@ -56,11 +134,12 @@ namespace Umbraco.Core.Logging
void Info(Type reporting, string message);
/// <summary>
/// Logs an information message.
/// Logs a info message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="messageBuilder">A message builder.</param>
void Info(Type reporting, Func<string> messageBuilder);
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Info(Type reporting, string messageTemplate, params object[] propertyValues);
/// <summary>
/// Logs a debugging message.
@@ -70,10 +149,26 @@ namespace Umbraco.Core.Logging
void Debug(Type reporting, string message);
/// <summary>
/// Logs a debugging message.
/// Logs a debug message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="messageBuilder">A message builder.</param>
void Debug(Type reporting, Func<string> messageBuilder);
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Debug(Type reporting, string messageTemplate, params object[] propertyValues);
/// <summary>
/// Logs a verbose message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="message">A message.</param>
void Verbose(Type reporting, string message);
/// <summary>
/// Logs a verbose message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Verbose(Type reporting, string messageTemplate, params object[] propertyValues);
}
}

View File

@@ -1,12 +0,0 @@
namespace Umbraco.Core.Logging
{
/// <summary>
/// Borrowed from https://github.com/cjbhaines/Log4Net.Async - will reference Nuget packages directly in v8
/// </summary>
/// <typeparam name="T"></typeparam>
internal interface IQueue<T>
{
void Enqueue(T item);
bool TryDequeue(out T ret);
}
}

View File

@@ -27,7 +27,7 @@ namespace Umbraco.Core.Logging
{
// Using LogHelper since the ImageProcessor logger expects a parameterless constructor.
var message = $"{callerName} {lineNumber} : {text}";
Current.Logger.Error<T>(string.Empty, new ImageProcessingException(message));
Current.Logger.Error<T>(new ImageProcessingException(message));
}
/// <summary>
@@ -41,7 +41,7 @@ namespace Umbraco.Core.Logging
{
// Using LogHelper since the ImageProcessor logger expects a parameterless constructor.
var message = $"{callerName} {lineNumber} : {text}";
Current.Logger.Error(type, string.Empty, new ImageProcessingException(message));
Current.Logger.Error(type, new ImageProcessingException(message));
}
}
}

View File

@@ -24,8 +24,8 @@ namespace Umbraco.Core.Logging
/// <inheritdoc/>
public IDisposable Step(string name)
{
_logger.Debug<LogProfiler>(() => $"Begin: {name}.");
return new LightDisposableTimer(duration => _logger.Info<LogProfiler>(() => $"End {name}. ({duration}ms)"));
_logger.Debug<LogProfiler>("Begin: {ProfileName}", name);
return new LightDisposableTimer(duration => _logger.Info<LogProfiler>("End {ProfileName} ({ProfileDuration}ms)", name, duration));
}
/// <inheritdoc/>

View File

@@ -1,61 +1,129 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using log4net;
using log4net.Config;
using Umbraco.Core.Configuration;
using Umbraco.Core.Diagnostics;
using log4net.Util;
using Serilog;
using Serilog.Events;
using Umbraco.Core.Logging.SerilogExtensions;
namespace Umbraco.Core.Logging
{
///<summary>
/// Implements <see cref="ILogger"/> on top of log4net.
/// Implements <see cref="ILogger"/> on top of Serilog.
///</summary>
public class Logger : ILogger
{
/// <summary>
/// Initialize a new instance of the <see cref="Logger"/> class with a log4net configuration file.
/// Initialize a new instance of the <see cref="Logger"/> class with a configuration file.
/// </summary>
/// <param name="log4NetConfigFile"></param>
public Logger(FileInfo log4NetConfigFile)
: this()
/// <param name="logConfigFile"></param>
public Logger(FileInfo logConfigFile)
{
XmlConfigurator.Configure(log4NetConfigFile);
Log.Logger = new LoggerConfiguration()
.ReadFrom.AppSettings(filePath: AppDomain.CurrentDomain.BaseDirectory + logConfigFile)
.CreateLogger();
}
// private for CreateWithDefaultLog4NetConfiguration
private Logger()
public Logger(LoggerConfiguration logConfig)
{
// add custom global properties to the log4net context that we can use in our logging output
GlobalContext.Properties["processId"] = Process.GetCurrentProcess().Id;
GlobalContext.Properties["appDomainId"] = AppDomain.CurrentDomain.Id;
//Configure Serilog static global logger with config passed in
Log.Logger = logConfig.CreateLogger();
}
/// <summary>
/// Creates a logger with the default log4net configuration discovered (i.e. from the web.config).
/// Creates a logger with some pre-definied configuration and remainder from config file
/// </summary>
/// <remarks>Used by UmbracoApplicationBase to get its logger.</remarks>
public static Logger CreateWithDefaultLog4NetConfiguration()
public static Logger CreateWithDefaultConfiguration()
{
return new Logger();
var loggerConfig = new LoggerConfiguration();
loggerConfig
.MinimalConfiguration()
.OutputDefaultTextFile(LogEventLevel.Debug)
.OutputDefaultJsonFile()
.ReadFromConfigFile()
.ReadFromUserConfigFile();
return new Logger(loggerConfig);
}
/// <inheritdoc/>
public void Error(Type reporting, string message, Exception exception = null)
public void Fatal(Type reporting, Exception exception, string message)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null) return;
Fatal(reporting, exception, message, null);
}
/// <inheritdoc/>
public void Fatal(Type reporting, Exception exception)
{
Fatal(reporting, exception, string.Empty);
}
/// <inheritdoc/>
public void Fatal(Type reporting, string message)
{
//Sometimes we need to throw an error without an ex
Fatal(reporting, null, message);
}
/// <inheritdoc/>
public void Fatal(Type reporting, string messageTemplate, params object[] propertyValues)
{
//Log a structured message WITHOUT an ex
Fatal(reporting, null, messageTemplate, propertyValues);
}
/// <inheritdoc/>
public void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues)
{
ErrorOrFatal(Fatal, exception, ref messageTemplate);
var logger = Log.Logger;
logger?.ForContext(reporting).Fatal(exception, messageTemplate, propertyValues);
}
/// <inheritdoc/>
public void Error(Type reporting, Exception exception, string message)
{
Error(reporting, exception, message, null);
}
/// <inheritdoc/>
public void Error(Type reporting, Exception exception)
{
Error(reporting, exception, string.Empty);
}
/// <inheritdoc/>
public void Error(Type reporting, string message)
{
//Sometimes we need to throw an error without an ex
Error(reporting, null, message);
}
/// <inheritdoc/>
public void Error(Type reporting, string messageTemplate, params object[] propertyValues)
{
//Log a structured message WITHOUT an ex
Error(reporting, null, messageTemplate, propertyValues);
}
/// <inheritdoc/>
public void Error(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues)
{
ErrorOrFatal(Error, exception, ref messageTemplate);
var logger = Log.Logger;
logger?.ForContext(reporting).Error(exception, messageTemplate, propertyValues);
}
private static void ErrorOrFatal(Action<Type, Exception, string, object[]> logAction, Exception exception, ref string messageTemplate)
{
var dump = false;
if (IsTimeoutThreadAbortException(exception))
{
message += "\r\nThe thread has been aborted, because the request has timed out.";
messageTemplate += "\r\nThe thread has been aborted, because the request has timed out.";
// dump if configured, or if stacktrace contains Monitor.ReliableEnter
dump = UmbracoConfig.For.CoreDebug().DumpOnTimeoutThreadAbort || IsMonitorEnterThreadAbortException(exception);
@@ -69,23 +137,22 @@ namespace Umbraco.Core.Logging
try
{
var dumped = MiniDump.Dump(withException: true);
message += dumped
messageTemplate += dumped
? "\r\nA minidump was created in App_Data/MiniDump"
: "\r\nFailed to create a minidump";
}
catch (Exception e)
catch (Exception ex)
{
message += string.Format("\r\nFailed to create a minidump ({0}: {1})", e.GetType().FullName, e.Message);
//Log a new entry (as opposed to appending to same log entry)
logAction(ex.GetType(), ex, "Failed to create a minidump at App_Data/MiniDump ({ExType}: {ExMessage}",
new object[]{ ex.GetType().FullName, ex.Message });
}
}
logger.Error(message, exception);
}
private static bool IsMonitorEnterThreadAbortException(Exception exception)
{
var abort = exception as ThreadAbortException;
if (abort == null) return false;
if (!(exception is ThreadAbortException abort)) return false;
var stacktrace = abort.StackTrace;
return stacktrace.Contains("System.Threading.Monitor.ReliableEnter");
@@ -93,8 +160,7 @@ namespace Umbraco.Core.Logging
private static bool IsTimeoutThreadAbortException(Exception exception)
{
var abort = exception as ThreadAbortException;
if (abort == null) return false;
if (!(exception is ThreadAbortException abort)) return false;
if (abort.ExceptionState == null) return false;
@@ -110,135 +176,67 @@ namespace Umbraco.Core.Logging
/// <inheritdoc/>
public void Warn(Type reporting, string format)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsWarnEnabled == false) return;
logger.Warn(format);
Warn(reporting, null, format);
}
/// <inheritdoc/>
public void Warn(Type reporting, Func<string> messageBuilder)
public void Warn(Type reporting, string messageTemplate, params object[] propertyValues)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsWarnEnabled == false) return;
logger.Warn(messageBuilder());
}
/// <inheritdoc/>
public void Warn(Type reporting, string format, params object[] args)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsWarnEnabled == false) return;
logger.WarnFormat(format, args);
}
/// <inheritdoc/>
public void Warn(Type reporting, string format, params Func<object>[] args)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsWarnEnabled == false) return;
logger.WarnFormat(format, args.Select(x => x.Invoke()).ToArray());
Warn(reporting, null, messageTemplate, propertyValues);
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, string message)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsWarnEnabled == false) return;
logger.Warn(message, exception);
Warn(reporting, exception, message, Array.Empty<object>());
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, Func<string> messageBuilder)
public void Warn(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsWarnEnabled == false) return;
logger.Warn(messageBuilder(), exception);
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, string format, params object[] args)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsWarnEnabled == false) return;
// there is no WarnFormat overload that accepts an exception
// format the message the way log4net would do it (see source code LogImpl.cs)
var message = new SystemStringFormat(CultureInfo.InvariantCulture, format, args);
logger.Warn(message, exception);
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, string format, params Func<object>[] args)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsWarnEnabled == false) return;
// there is no WarnFormat overload that accepts an exception
// format the message the way log4net would do it (see source code LogImpl.cs)
var message = new SystemStringFormat(CultureInfo.InvariantCulture, format, args.Select(x => x.Invoke()).ToArray());
logger.Warn(message, exception);
var logger = Log.Logger;
logger?.ForContext(reporting).Warning(exception, messageTemplate, propertyValues);
}
/// <inheritdoc/>
public void Info(Type reporting, string message)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsInfoEnabled == false) return;
logger.Info(message);
Info(reporting, message, Array.Empty<object>());
}
/// <inheritdoc/>
public void Info(Type reporting, Func<string> generateMessage)
public void Info(Type reporting, string messageTemplate, params object[] propertyValues)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsInfoEnabled == false) return;
logger.Info(generateMessage());
}
/// <inheritdoc/>
public void Info(Type reporting, string format, params object[] args)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsInfoEnabled == false) return;
logger.InfoFormat(format, args);
}
/// <inheritdoc/>
public void Info(Type reporting, string format, params Func<object>[] args)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsInfoEnabled == false) return;
logger.InfoFormat(format, args.Select(x => x.Invoke()).ToArray());
var logger = Log.Logger;
logger?.ForContext(reporting).Information(messageTemplate, propertyValues);
}
/// <inheritdoc/>
public void Debug(Type reporting, string message)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsDebugEnabled == false) return;
logger.Debug(message);
Debug(reporting, message, Array.Empty<object>());
}
/// <inheritdoc/>
public void Debug(Type reporting, string messageTemplate, params object[] propertyValues)
{
var logger = Log.Logger;
logger?.ForContext(reporting).Debug(messageTemplate, propertyValues);
}
/// <inheritdoc/>
public void Debug(Type reporting, Func<string> messageBuilder)
public void Verbose(Type reporting, string message)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsDebugEnabled == false) return;
logger.Debug(messageBuilder());
Verbose(reporting, message, Array.Empty<object>());
}
/// <inheritdoc/>
public void Debug(Type reporting, string format, params object[] args)
public void Verbose(Type reporting, string messageTemplate, params object[] propertyValues)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsDebugEnabled == false) return;
logger.DebugFormat(format, args);
var logger = Log.Logger;
logger?.ForContext(reporting).Verbose(messageTemplate, propertyValues);
}
/// <inheritdoc/>
public void Debug(Type reporting, string format, params Func<object>[] args)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsDebugEnabled == false) return;
logger.DebugFormat(format, args.Select(x => x.Invoke()).ToArray());
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Linq;
namespace Umbraco.Core.Logging
{
@@ -9,15 +8,62 @@ namespace Umbraco.Core.Logging
public static class LoggerExtensions
{
/// <summary>
/// Logs an error message.
/// Logs an error message
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="message">A message.</param>
/// <param name="exception">An exception.</param>
public static void Error<T>(this ILogger logger, string message, Exception exception = null)
public static void Error<T>(this ILogger logger, Exception exception, string message)
{
logger.Error(typeof(T), message, exception);
logger.Error(typeof(T), exception, message);
}
/// <summary>
/// Logs an error message with a structured message template
/// </summary>
/// <typeparam name="T">The reporting type</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageTemplate">A structured message template</param>
/// <param name="exception">An exception</param>
/// <param name="propertyValues">Message property values</param>
public static void Error<T>(this ILogger logger, Exception exception, string messageTemplate, params object[] propertyValues)
{
logger.Error(typeof(T), exception, messageTemplate, propertyValues);
}
/// <summary>
/// Logs an error message NOTE: This will log an empty message string
/// </summary>
/// <typeparam name="T">The reporting type</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="exception">An exception</param>
public static void Error<T>(this ILogger logger, Exception exception)
{
logger.Error(typeof(T), exception);
}
/// <summary>
/// Logs an error message WITHOUT EX
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="logger"></param>
/// <param name="message"></param>
public static void Error<T>(this ILogger logger, string message)
{
logger.Error(typeof(T), message);
}
/// <summary>
/// Logs an error message - using a structured log message
/// </summary>
/// <typeparam name="T">The reporting type</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageTemplate">A structured message template</param>
/// <param name="propertyValues">Message property values</param>
public static void Error<T>(this ILogger logger, string messageTemplate, params object[] propertyValues)
{
logger.Error(typeof(T), messageTemplate, propertyValues);
}
/// <summary>
@@ -32,26 +78,15 @@ namespace Umbraco.Core.Logging
}
/// <summary>
/// Logs a warning message.
/// Logs a warning message with a structured message template
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <typeparam name="T">The reporting type</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageBuilder">A message builder.</param>
public static void Warn<T>(this ILogger logger, Func<string> messageBuilder)
/// <param name="messageTemplate">A structured message template</param>
/// <param name="propertyValues">Message property values</param>
public static void Warn<T>(this ILogger logger, string messageTemplate, params object[] propertyValues)
{
logger.Warn(typeof(T), messageBuilder);
}
/// <summary>
/// Logs a formatted warning message with an exception.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="exception">An exception.</param>
/// <param name="messageBuilder">A message builder.</param>
public static void Warn<T>(this ILogger logger, Exception exception, Func<string> messageBuilder)
{
logger.Warn(typeof(T), exception, messageBuilder);
logger.Warn(typeof(T), messageTemplate, propertyValues);
}
/// <summary>
@@ -66,6 +101,19 @@ namespace Umbraco.Core.Logging
logger.Warn(typeof(T), exception, message);
}
/// <summary>
/// Logs a warning message with an exception with a structured message template
/// </summary>
/// <typeparam name="T">The reporting type</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="exception">An exception</param>
/// <param name="messageTemplate">A structured message template</param>
/// <param name="propertyValues">Message property values</param>
public static void Warn<T>(this ILogger logger, Exception exception, string messageTemplate, params object[] propertyValues)
{
logger.Warn(typeof(T), exception, messageTemplate, propertyValues);
}
/// <summary>
/// Logs an information message.
/// </summary>
@@ -78,14 +126,15 @@ namespace Umbraco.Core.Logging
}
/// <summary>
/// Logs an information message.
/// Logs a information message with a structured message template
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <typeparam name="T">The reporting type</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageBuilder">A message builder.</param>
public static void Info<T>(this ILogger logger, Func<string> messageBuilder)
/// <param name="messageTemplate">A structured message template</param>
/// <param name="propertyValues">Message property values</param>
public static void Info<T>(this ILogger logger, string messageTemplate, params object[] propertyValues)
{
logger.Info(typeof(T), messageBuilder);
logger.Info(typeof(T), messageTemplate, propertyValues);
}
/// <summary>
@@ -100,14 +149,66 @@ namespace Umbraco.Core.Logging
}
/// <summary>
/// Logs a debugging message.
/// Logs a debugging message with a structured message template
/// </summary>
/// <typeparam name="T">The reporting type</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageTemplate">A structured message template</param>
/// <param name="propertyValues">Message property values</param>
public static void Debug<T>(this ILogger logger, string messageTemplate, params object[] propertyValues)
{
logger.Debug(typeof(T), messageTemplate, propertyValues);
}
/// <summary>
/// Logs a verbose message.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageBuilder">A message builder.</param>
public static void Debug<T>(this ILogger logger, Func<string> messageBuilder)
/// <param name="message">A message.</param>
public static void Verbose<T>(this ILogger logger, string message)
{
logger.Debug(typeof(T), messageBuilder);
logger.Verbose(typeof(T), message);
}
/// <summary>
/// Logs a Verbose message with a structured message template
/// </summary>
/// <typeparam name="T">The reporting type</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageTemplate">A structured message template</param>
/// <param name="propertyValues">Message property values</param>
public static void Verbose<T>(this ILogger logger, string messageTemplate, params object[] propertyValues)
{
logger.Verbose(typeof(T), messageTemplate, propertyValues);
}
/// <summary>
/// Logs a fatal message.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="exception">An exception.</param>
/// <param name="message">A message.</param>
public static void Fatal<T>(this ILogger logger, Exception exception, string message)
{
logger.Fatal(typeof(T), exception, message);
}
/// <summary>
/// Logs a fatal message with a structured message template
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="exception">An exception.</param>
/// <param name="messageTemplate">A structured message template</param>
/// <param name="propertyValues">Message property values</param>
public static void Fatal<T>(this ILogger logger, Exception exception, string messageTemplate, params object[] propertyValues)
{
logger.Fatal(typeof(T), exception, messageTemplate, propertyValues);
}
}
}

View File

@@ -1,20 +0,0 @@
using log4net.Core;
namespace Umbraco.Core.Logging
{
/// <remarks>
/// Borrowed from https://github.com/cjbhaines/Log4Net.Async - will reference Nuget packages directly in v8
/// </remarks>
internal sealed class LoggingEventContext
{
public LoggingEventContext(LoggingEvent loggingEvent, object httpContext)
{
LoggingEvent = loggingEvent;
HttpContext = httpContext;
}
public LoggingEvent LoggingEvent { get; set; }
public object HttpContext { get; set; }
}
}

View File

@@ -1,33 +0,0 @@
using System;
using log4net.Core;
namespace Umbraco.Core.Logging
{
/// <remarks>
/// Borrowed from https://github.com/cjbhaines/Log4Net.Async - will reference Nuget packages directly in v8
/// </remarks>
internal sealed class LoggingEventHelper
{
// needs to be a seperate class so that location is determined correctly by log4net when required
private static readonly Type HelperType = typeof(LoggingEventHelper);
private readonly string loggerName;
public FixFlags Fix { get; set; }
public LoggingEventHelper(string loggerName, FixFlags fix)
{
this.loggerName = loggerName;
Fix = fix;
}
public LoggingEvent CreateLoggingEvent(Level level, string message, Exception exception)
{
var loggingEvent = new LoggingEvent(HelperType, null, loggerName, level, message, exception)
{
Fix = Fix
};
return loggingEvent;
}
}
}

View File

@@ -26,34 +26,34 @@ namespace Umbraco.Core.Logging
switch (eventType)
{
case TraceEventType.Critical:
_logger.Error(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state), exception ?? new Exception("Critical error"));
_logger.Fatal(_type.Value, exception, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
return true;
case TraceEventType.Error:
_logger.Error(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state), exception ?? new Exception("Error"));
_logger.Error(_type.Value, exception, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
return true;
case TraceEventType.Warning:
_logger.Warn(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
_logger.Warn(_type.Value, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
return true;
case TraceEventType.Information:
_logger.Info(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
_logger.Info(_type.Value, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
return true;
case TraceEventType.Verbose:
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
_logger.Debug(_type.Value, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
return true;
case TraceEventType.Start:
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
_logger.Debug(_type.Value, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
return true;
case TraceEventType.Stop:
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
_logger.Debug(_type.Value, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
return true;
case TraceEventType.Suspend:
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
_logger.Debug(_type.Value, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
return true;
case TraceEventType.Resume:
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
_logger.Debug(_type.Value, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
return true;
case TraceEventType.Transfer:
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
_logger.Debug(_type.Value, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
return true;
default:
throw new ArgumentOutOfRangeException("eventType");

View File

@@ -1,78 +0,0 @@
using System;
namespace Umbraco.Core.Logging
{
/// <summary>
/// Borrowed from https://github.com/cjbhaines/Log4Net.Async - will reference Nuget packages directly in v8
/// </summary>
/// <typeparam name="T"></typeparam>
internal sealed class RingBuffer<T> : IQueue<T>
{
private readonly object lockObject = new object();
private readonly T[] buffer;
private readonly int size;
private int readIndex = 0;
private int writeIndex = 0;
private bool bufferFull = false;
public int Size { get { return size; } }
public event Action<object, EventArgs> BufferOverflow;
public RingBuffer(int size)
{
this.size = size;
buffer = new T[size];
}
public void Enqueue(T item)
{
var bufferWasFull = false;
lock (lockObject)
{
buffer[writeIndex] = item;
writeIndex = (++writeIndex) % size;
if (bufferFull)
{
bufferWasFull = true;
readIndex = writeIndex;
}
else if (writeIndex == readIndex)
{
bufferFull = true;
}
}
if (bufferWasFull)
{
if (BufferOverflow != null)
{
BufferOverflow(this, EventArgs.Empty);
}
}
}
public bool TryDequeue(out T ret)
{
if (readIndex == writeIndex && !bufferFull)
{
ret = default(T);
return false;
}
lock (lockObject)
{
if (readIndex == writeIndex && !bufferFull)
{
ret = default(T);
return false;
}
ret = buffer[readIndex];
buffer[readIndex] = default(T);
readIndex = (++readIndex) % size;
bufferFull = false;
return true;
}
}
}
}

View File

@@ -1,95 +0,0 @@
using System;
using System.IO;
using log4net.Appender;
using log4net.Util;
namespace Umbraco.Core.Logging
{
/// <summary>
/// This class will do the exact same thing as the RollingFileAppender that comes from log4net
/// With the extension, that it is able to do automatic cleanup of the logfiles in the directory where logging happens
///
/// By specifying the properties MaxLogFileDays and BaseFilePattern, the files will automaticly get deleted when
/// the logger is configured(typically when the app starts). To utilize this appender swap out the type of the rollingFile appender
/// that ships with Umbraco, to be Umbraco.Core.Logging.RollingFileCleanupAppender, and add the maxLogFileDays and baseFilePattern elements
/// to the configuration i.e.:
///
/// <example>
/// <appender name="rollingFile" type="Log4netAwesomeness.CustomRollingFileAppender, Log4netAwesomeness">
/// <file type="log4net.Util.PatternString" value="App_Data\Logs\UmbracoTraceLog.%property{log4net:HostName}.txt" />
/// <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
/// <appendToFile value="true" />
/// <rollingStyle value="Date" />
/// <maximumFileSize value="5MB" />
/// <maxLogFileDays value="5"/>
/// <basefilePattern value="UmbracoTraceLog.*.txt.*"/>
/// <layout type="log4net.Layout.PatternLayout">
/// <conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
/// </layout>
/// <layout type="log4net.Layout.PatternLayout">
/// <conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
/// </layout>
/// <encoding value="utf-8" />
/// </appender>
/// </example>
/// </summary>
public class RollingFileCleanupAppender : RollingFileAppender
{
public int MaxLogFileDays { get; set; }
public string BaseFilePattern { get; set; }
/// <summary>
/// This override will delete logs older than the specified amount of days
/// </summary>
/// <param name="fileName"></param>
/// <param name="append"></param>
protected override void OpenFile(string fileName, bool append)
{
bool cleanup = true;
// Validate settings and input
if (MaxLogFileDays <= 0)
{
LogLog.Warn(typeof(RollingFileCleanupAppender), "Parameter 'MaxLogFileDays' needs to be a positive integer, aborting cleanup");
cleanup = false;
}
if (string.IsNullOrWhiteSpace(BaseFilePattern))
{
LogLog.Warn(typeof(RollingFileCleanupAppender), "Parameter 'BaseFilePattern' is empty, aborting cleanup");
cleanup = false;
}
// grab the directory we are logging to, as this is were we will search for older logfiles
var logFolder = Path.GetDirectoryName(fileName);
if (Directory.Exists(logFolder) == false)
{
LogLog.Warn(typeof(RollingFileCleanupAppender), string.Format("Directory '{0}' for logfiles does not exist, aborting cleanup", logFolder));
cleanup = false;
}
// If everything is validated, we can do the actual cleanup
if (cleanup)
{
Cleanup(logFolder);
}
base.OpenFile(fileName, append);
}
private void Cleanup(string directoryPath)
{
// only take files that matches the pattern we are using i.e. UmbracoTraceLog.*.txt.*
string[] logFiles = Directory.GetFiles(directoryPath, BaseFilePattern);
LogLog.Debug(typeof(RollingFileCleanupAppender), string.Format("Found {0} files that matches the baseFilePattern: '{1}'", logFiles.Length, BaseFilePattern));
foreach (var logFile in logFiles)
{
DateTime lastAccessTime = System.IO.File.GetLastWriteTimeUtc(logFile);
// take the value from the config file
if (lastAccessTime < DateTime.Now.AddDays(-MaxLogFileDays))
{
LogLog.Debug(typeof(RollingFileCleanupAppender), string.Format("Deleting file {0} as its lastAccessTime is older than {1} days speficied by MaxLogFileDays", logFile, MaxLogFileDays));
base.DeleteFile(logFile);
}
}
}
}
}

View File

@@ -0,0 +1,49 @@
using Serilog.Core;
using Serilog.Events;
namespace Umbraco.Core.Logging.SerilogExtensions
{
/// <summary>
/// This is used to create a new property in Logs called 'Log4NetLevel'
/// So that we can map Serilog levels to Log4Net levels - so log files stay consistent
/// </summary>
internal class Log4NetLevelMapperEnricher : ILogEventEnricher
{
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
var log4NetLevel = string.Empty;
switch (logEvent.Level)
{
case LogEventLevel.Debug:
log4NetLevel = "DEBUG";
break;
case LogEventLevel.Error:
log4NetLevel = "ERROR";
break;
case LogEventLevel.Fatal:
log4NetLevel = "FATAL";
break;
case LogEventLevel.Information:
log4NetLevel = "INFO";
break;
case LogEventLevel.Verbose:
log4NetLevel = "ALL";
break;
case LogEventLevel.Warning:
log4NetLevel = "WARN";
break;
}
//Pad string so that all log levels are 5 chars long (needed to keep the txt log file lined up nicely)
log4NetLevel = log4NetLevel.PadRight(5);
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("Log4NetLevel", log4NetLevel));
}
}
}

View File

@@ -0,0 +1,103 @@
using System;
using System.Web;
using Serilog;
using Serilog.Events;
using Serilog.Formatting.Compact;
namespace Umbraco.Core.Logging.SerilogExtensions
{
public static class LoggerConfigExtensions
{
/// <summary>
/// This configures Serilog with some defaults
/// Such as adding ProcessID, Thread, AppDomain etc
/// It is highly recommended that you keep/use this default in your own logging config customizations
/// </summary>
/// <param name="logConfig">A Serilog LoggerConfiguration</param>
public static LoggerConfiguration MinimalConfiguration(this LoggerConfiguration logConfig)
{
Serilog.Debugging.SelfLog.Enable(msg => System.Diagnostics.Debug.WriteLine(msg));
//Set this environment variable - so that it can be used in external config file
//add key="serilog:write-to:RollingFile.pathFormat" value="%BASEDIR%\logs\log.txt" />
Environment.SetEnvironmentVariable("BASEDIR", AppDomain.CurrentDomain.BaseDirectory, EnvironmentVariableTarget.Process);
logConfig.MinimumLevel.Verbose() //Set to highest level of logging (as any sinks may want to restrict it to Errors only)
.Enrich.WithProcessId()
.Enrich.WithProcessName()
.Enrich.WithThreadId()
.Enrich.WithProperty("AppDomainId", AppDomain.CurrentDomain.Id)
.Enrich.WithProperty("AppDomainAppId", HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty))
.Enrich.WithProperty("MachineName", Environment.MachineName)
.Enrich.With<Log4NetLevelMapperEnricher>();
return logConfig;
}
/// <summary>
/// Outputs a .txt format log at /App_Data/Logs/
/// </summary>
/// <param name="logConfig">A Serilog LoggerConfiguration</param>
/// <param name="minimumLevel">The log level you wish the JSON file to collect - default is Verbose (highest)</param>
/// <param name="retainedFileCount">The number of days to keep log files. Default is set to null which means all logs are kept</param>
public static LoggerConfiguration OutputDefaultTextFile(this LoggerConfiguration logConfig, LogEventLevel minimumLevel = LogEventLevel.Verbose, int? retainedFileCount = null)
{
//Main .txt logfile - in similar format to older Log4Net output
//Ends with ..txt as Date is inserted before file extension substring
logConfig.WriteTo.File($@"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\UmbracoTraceLog.{Environment.MachineName}..txt",
shared: true,
rollingInterval: RollingInterval.Day,
restrictedToMinimumLevel: minimumLevel,
retainedFileCountLimit: null, //Setting to null means we keep all files - default is 31 days
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss,fff} [P{ProcessId}/D{AppDomainId}/T{ThreadId}] {Log4NetLevel} {SourceContext} - {Message:lj}{NewLine}{Exception}");
return logConfig;
}
/// <summary>
/// Outputs a CLEF format JSON log at /App_Data/Logs/
/// </summary>
/// <param name="logConfig">A Serilog LoggerConfiguration</param>
/// <param name="minimumLevel">The log level you wish the JSON file to collect - default is Verbose (highest)</param>
/// <param name="retainedFileCount">The number of days to keep log files. Default is set to null which means all logs are kept</param>
public static LoggerConfiguration OutputDefaultJsonFile(this LoggerConfiguration logConfig, LogEventLevel minimumLevel = LogEventLevel.Verbose, int? retainedFileCount = null)
{
//.clef format (Compact log event format, that can be imported into local SEQ & will make searching/filtering logs easier)
//Ends with ..txt as Date is inserted before file extension substring
logConfig.WriteTo.File(new CompactJsonFormatter(), $@"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\UmbracoTraceLog.{Environment.MachineName}..json",
shared: true,
rollingInterval: RollingInterval.Day, //Create a new JSON file every day
retainedFileCountLimit: retainedFileCount, //Setting to null means we keep all files - default is 31 days
restrictedToMinimumLevel: minimumLevel);
return logConfig;
}
/// <summary>
/// Reads settings from /config/serilog.config
/// That allows the main logging pipeline to be configured
/// </summary>
/// <param name="logConfig">A Serilog LoggerConfiguration</param>
public static LoggerConfiguration ReadFromConfigFile(this LoggerConfiguration logConfig)
{
//Read from main serilog.config file
logConfig.ReadFrom.AppSettings(filePath: AppDomain.CurrentDomain.BaseDirectory + @"\config\serilog.config");
return logConfig;
}
/// <summary>
/// Reads settings from /config/serilog.user.config
/// That allows a seperate logging pipeline to be configured that wil not affect the main Umbraco log
/// </summary>
/// <param name="logConfig">A Serilog LoggerConfiguration</param>
public static LoggerConfiguration ReadFromUserConfigFile(this LoggerConfiguration logConfig)
{
//A nested logger - where any user configured sinks via config can not effect the main 'umbraco' logger above
logConfig.WriteTo.Logger(cfg =>
cfg.ReadFrom.AppSettings(filePath: AppDomain.CurrentDomain.BaseDirectory + @"\config\serilog.user.config"));
return logConfig;
}
}
}

View File

@@ -117,7 +117,7 @@ namespace Umbraco.Core
lock (_locko)
{
_logger.Debug<MainDom>(() => "Signaled" + (_signaled ? " (again)" : "") + " (" + source + ").");
_logger.Debug<MainDom>("Signaled {Signaled} ({SignalSource})", _signaled ? "(again)" : string.Empty, source);
if (_signaled) return;
if (_isMainDom == false) return; // probably not needed
_signaled = true;
@@ -125,7 +125,7 @@ namespace Umbraco.Core
try
{
_logger.Info<MainDom>("Stopping.");
_logger.Info<MainDom>("Stopping ({SignalSource})", source);
foreach (var callback in _callbacks.OrderBy(x => x.Key).Select(x => x.Value))
{
try
@@ -134,19 +134,19 @@ namespace Umbraco.Core
}
catch (Exception e)
{
_logger.Error<MainDom>("Error while running callback, remaining callbacks will not run.", e);
_logger.Error<MainDom>(e, "Error while running callback, remaining callbacks will not run.");
throw;
}
}
_logger.Debug<MainDom>("Stopped.");
_logger.Debug<MainDom>("Stopped ({SignalSource})", source);
}
finally
{
// in any case...
_isMainDom = false;
_asyncLocker.Dispose();
_logger.Info<MainDom>("Released.");
_logger.Info<MainDom>("Released ({SignalSource})", source);
}
}

View File

@@ -81,7 +81,7 @@ namespace Umbraco.Core.Manifest
}
catch (Exception e)
{
_logger.Error<ManifestParser>($"Failed to parse manifest at \"{path}\", ignoring.", e);
_logger.Error<ManifestParser>(e, "Failed to parse manifest at '{Path}', ignoring.", path);
}
}

View File

@@ -54,7 +54,7 @@ namespace Umbraco.Core.Manifest
if (_isRestarting) return;
_isRestarting = true;
_logger.Info<ManifestWatcher>("manifest has changed, app pool is restarting (" + e.FullPath + ")");
_logger.Info<ManifestWatcher>("Manifest has changed, app pool is restarting ({Path})", e.FullPath);
HttpRuntime.UnloadAppDomain();
Dispose(); // uh? if the app restarts then this should be disposed anyways?
}

View File

@@ -153,7 +153,7 @@ namespace Umbraco.Core.Media
}
catch (Exception ex)
{
_logger.Error(typeof(UploadAutoFillProperties), $"Could not populate upload auto-fill properties for file \"{filepath}\".", ex);
_logger.Error(typeof(UploadAutoFillProperties), ex, "Could not populate upload auto-fill properties for file '{File}'.", filepath);
ResetProperties(content, autoFillConfig, culture, segment);
}
}

View File

@@ -309,7 +309,7 @@ namespace Umbraco.Core.Migrations.Install
{
var source = connectionStrings.Attribute("configSource").Value;
var configFile = IOHelper.MapPath($"{SystemDirectories.Root}/{source}");
logger.Info<DatabaseBuilder>(() => $"Storing ConnectionString in {configFile}");
logger.Info<DatabaseBuilder>("Storing ConnectionString in {ConfigFile}", configFile);
if (File.Exists(configFile))
{
xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
@@ -335,7 +335,7 @@ namespace Umbraco.Core.Migrations.Install
}
xml.Save(fileName, SaveOptions.DisableFormatting);
logger.Info<DatabaseBuilder>(() => $"Configured a new ConnectionString using the '{providerName}' provider.");
logger.Info<DatabaseBuilder>("Configured a new ConnectionString using the '{ProviderName}' provider.", providerName);
}
internal bool IsConnectionStringConfigured(ConnectionStringSettings databaseSettings)
@@ -500,7 +500,7 @@ namespace Umbraco.Core.Migrations.Install
message = message + "<p>Installation completed!</p>";
//now that everything is done, we need to determine the version of SQL server that is executing
_logger.Info<DatabaseBuilder>(() => $"Database configuration status: {message}");
_logger.Info<DatabaseBuilder>("Database configuration status: {DbConfigStatus}", message);
return new Result { Message = message, Success = true, Percentage = "100" };
}
@@ -589,7 +589,7 @@ namespace Umbraco.Core.Migrations.Install
//now that everything is done, we need to determine the version of SQL server that is executing
_logger.Info<DatabaseBuilder>(() => $"Database configuration status: {message}");
_logger.Info<DatabaseBuilder>("Database configuration status: {DbConfigStatus}", message);
return new Result { Message = message, Success = true, Percentage = "100" };
}
@@ -658,11 +658,11 @@ namespace Umbraco.Core.Migrations.Install
private Result HandleInstallException(Exception ex)
{
_logger.Error<DatabaseBuilder>("Database configuration failed", ex);
_logger.Error<DatabaseBuilder>(ex, "Database configuration failed");
if (_databaseSchemaValidationResult != null)
{
_logger.Info<DatabaseBuilder>(() => $"The database schema validation produced the following summary: {Environment.NewLine}{_databaseSchemaValidationResult.GetSummary()}");
_logger.Info<DatabaseBuilder>("The database schema validation produced the following summary: {DbSchemaSummary}", _databaseSchemaValidationResult.GetSummary());
}
return new Result

View File

@@ -29,7 +29,7 @@ namespace Umbraco.Core.Migrations.Install
/// <param name="tableName">Name of the table to create base data for</param>
public void InitializeBaseData(string tableName)
{
_logger.Info<DatabaseDataCreator>(() => $"Creating data in table {tableName}");
_logger.Info<DatabaseDataCreator>("Creating data in {TableName}", tableName);
if (tableName.Equals(Constants.DatabaseSchema.Tables.Node))
CreateNodeData();
@@ -76,7 +76,7 @@ namespace Umbraco.Core.Migrations.Install
if (tableName.Equals(Constants.DatabaseSchema.Tables.KeyValue))
CreateKeyValueData();
_logger.Info<DatabaseDataCreator>(() => $"Done creating table {tableName} data.");
_logger.Info<DatabaseDataCreator>("Done creating table {TableName} data.", tableName);
}
private void CreateNodeData()

View File

@@ -98,7 +98,7 @@ namespace Umbraco.Core.Migrations.Install
var tableNameAttribute = table.FirstAttribute<TableNameAttribute>();
var tableName = tableNameAttribute == null ? table.Name : tableNameAttribute.Value;
_logger.Info<DatabaseSchemaCreator>(() => $"Uninstall {tableName}");
_logger.Info<DatabaseSchemaCreator>("Uninstall {TableName}", tableName);
try
{
@@ -109,7 +109,7 @@ namespace Umbraco.Core.Migrations.Install
{
//swallow this for now, not sure how best to handle this with diff databases... though this is internal
// and only used for unit tests. If this fails its because the table doesn't exist... generally!
_logger.Error<DatabaseSchemaCreator>("Could not drop table " + tableName, ex);
_logger.Error<DatabaseSchemaCreator>(ex, "Could not drop table {TableName}", tableName);
}
}
}
@@ -141,13 +141,7 @@ namespace Umbraco.Core.Migrations.Install
//get the db index defs
result.DbIndexDefinitions = SqlSyntax.GetDefinedIndexes(_database)
.Select(x => new DbIndexDefinition
{
TableName = x.Item1,
IndexName = x.Item2,
ColumnName = x.Item3,
IsUnique = x.Item4
}).ToArray();
.Select(x => new DbIndexDefinition(x)).ToArray();
result.TableDefinitions.AddRange(OrderedTables
.Select(x => DefinitionFactory.GetTableDefinition(x, SqlSyntax)));
@@ -160,6 +154,14 @@ namespace Umbraco.Core.Migrations.Install
return result;
}
/// <summary>
/// This validates the Primary/Foreign keys in the database
/// </summary>
/// <param name="result"></param>
/// <remarks>
/// This does not validate any database constraints that are not PKs or FKs because Umbraco does not create a database with non PK/FK contraints.
/// Any unique "constraints" in the database are done with unique indexes.
/// </remarks>
private void ValidateDbConstraints(DatabaseSchemaResult result)
{
//MySql doesn't conform to the "normal" naming of constraints, so there is currently no point in doing these checks.
@@ -172,8 +174,7 @@ namespace Umbraco.Core.Migrations.Install
var constraintsInDatabase = SqlSyntax.GetConstraintsPerColumn(_database).DistinctBy(x => x.Item3).ToList();
var foreignKeysInDatabase = constraintsInDatabase.Where(x => x.Item3.InvariantStartsWith("FK_")).Select(x => x.Item3).ToList();
var primaryKeysInDatabase = constraintsInDatabase.Where(x => x.Item3.InvariantStartsWith("PK_")).Select(x => x.Item3).ToList();
var indexesInDatabase = constraintsInDatabase.Where(x => x.Item3.InvariantStartsWith("IX_")).Select(x => x.Item3).ToList();
var indexesInSchema = result.TableDefinitions.SelectMany(x => x.Indexes.Select(y => y.Name)).ToList();
var unknownConstraintsInDatabase =
constraintsInDatabase.Where(
x =>
@@ -188,7 +189,7 @@ namespace Umbraco.Core.Migrations.Install
// In theory you could have: FK_ or fk_ ...or really any standard that your development department (or developer) chooses to use.
foreach (var unknown in unknownConstraintsInDatabase)
{
if (foreignKeysInSchema.InvariantContains(unknown) || primaryKeysInSchema.InvariantContains(unknown) || indexesInSchema.InvariantContains(unknown))
if (foreignKeysInSchema.InvariantContains(unknown) || primaryKeysInSchema.InvariantContains(unknown))
{
result.ValidConstraints.Add(unknown);
}
@@ -230,23 +231,6 @@ namespace Umbraco.Core.Migrations.Install
result.Errors.Add(new Tuple<string, string>("Constraint", primaryKey));
}
//Constaints:
//NOTE: SD: The colIndex checks above should really take care of this but I need to keep this here because it was here before
// and some schema validation checks might rely on this data remaining here!
//Add valid and invalid index differences to the result object
var validIndexDifferences = indexesInDatabase.Intersect(indexesInSchema, StringComparer.InvariantCultureIgnoreCase);
foreach (var index in validIndexDifferences)
{
result.ValidConstraints.Add(index);
}
var invalidIndexDifferences =
indexesInDatabase.Except(indexesInSchema, StringComparer.InvariantCultureIgnoreCase)
.Union(indexesInSchema.Except(indexesInDatabase, StringComparer.InvariantCultureIgnoreCase));
foreach (var index in invalidIndexDifferences)
{
result.Errors.Add(new Tuple<string, string>("Constraint", index));
}
}
private void ValidateDbColumns(DatabaseSchemaResult result)
@@ -392,13 +376,13 @@ namespace Umbraco.Core.Migrations.Install
{
//Execute the Create Table sql
var created = _database.Execute(new Sql(createSql));
_logger.Info<DatabaseSchemaCreator>(() => $"Create Table '{tableName}' ({created}):\n {createSql}");
_logger.Info<DatabaseSchemaCreator>("Create Table '{TableName}' ({Created}): \n {Sql}", tableName, created, createSql);
//If any statements exists for the primary key execute them here
if (string.IsNullOrEmpty(createPrimaryKeySql) == false)
{
var createdPk = _database.Execute(new Sql(createPrimaryKeySql));
_logger.Info<DatabaseSchemaCreator>(() => $"Create Primary Key ({createdPk}):\n {createPrimaryKeySql}");
_logger.Info<DatabaseSchemaCreator>("Create Primary Key ({CreatedPk}):\n {Sql}", createdPk, createPrimaryKeySql);
}
//Turn on identity insert if db provider is not mysql
@@ -424,21 +408,21 @@ namespace Umbraco.Core.Migrations.Install
foreach (var sql in indexSql)
{
var createdIndex = _database.Execute(new Sql(sql));
_logger.Info<DatabaseSchemaCreator>(() => $"Create Index ({createdIndex}):\n {sql}");
_logger.Info<DatabaseSchemaCreator>("Create Index ({CreatedIndex}):\n {Sql}", createdIndex, sql);
}
//Loop through foreignkey statements and execute sql
foreach (var sql in foreignSql)
{
var createdFk = _database.Execute(new Sql(sql));
_logger.Info<DatabaseSchemaCreator>(() => $"Create Foreign Key ({createdFk}):\n {sql}");
_logger.Info<DatabaseSchemaCreator>("Create Foreign Key ({CreatedFk}):\n {Sql}", createdFk, sql);
}
transaction.Complete();
}
}
_logger.Info<DatabaseSchemaCreator>(() => $"Created table '{tableName}'");
_logger.Info<DatabaseSchemaCreator>("Created table '{TableName}'", tableName);
}
public void DropTable(string tableName)

View File

@@ -55,7 +55,7 @@ namespace Umbraco.Core.Migrations
if (string.IsNullOrWhiteSpace(sql))
{
Logger.Info(GetType(), $"SQL [{Context.Index}]: <empty>");
Logger.Info(GetType(), "SQL [{ContextIndex}: <empty>", Context.Index);
}
else
{
@@ -90,7 +90,7 @@ namespace Umbraco.Core.Migrations
private void ExecuteStatement(StringBuilder stmtBuilder)
{
var stmt = stmtBuilder.ToString();
Logger.Info(GetType(), $"SQL [{Context.Index}]: {stmt}");
Logger.Info(GetType(), "SQL [{ContextIndex}]: {Sql}", Context.Index, stmt);
Database.Execute(stmt);
stmtBuilder.Clear();
}

View File

@@ -269,14 +269,11 @@ namespace Umbraco.Core.Migrations
if (_migrationBuilder == null || _logger == null)
throw new InvalidOperationException("Cannot execute a non-executing plan.");
_logger.Info<MigrationPlan>(() => $"Starting \"{Name}\"...");
_logger.Info<MigrationPlan>("Starting '{MigrationName}'...", Name);
var origState = fromState ?? string.Empty;
_logger.Info<MigrationPlan>(() =>
{
var info = "At " + (string.IsNullOrWhiteSpace(origState) ? "origin" : ("\"" + origState + "\"")) + ".";
return info.Replace("{", "{{").Replace("}", "}}"); // stupid log4net
});
_logger.Info<MigrationPlan>("At {OrigState}", string.IsNullOrWhiteSpace(origState) ? "origin": origState);
if (!_transitions.TryGetValue(origState, out var transition))
throw new Exception($"Unknown state \"{origState}\".");
@@ -291,7 +288,7 @@ namespace Umbraco.Core.Migrations
var nextState = transition.TargetState;
origState = nextState;
_logger.Info<MigrationPlan>(() => $"At \"{origState}\".");
_logger.Info<MigrationPlan>("At {OrigState}", origState);
if (!_transitions.TryGetValue(origState, out transition))
throw new Exception($"Unknown state \"{origState}\".");

View File

@@ -1,5 +1,4 @@
using System;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_7_12_0
{
@@ -12,20 +11,22 @@ namespace Umbraco.Core.Migrations.Upgrade.V_7_12_0
public override void Migrate()
{
var exists = Context.Database.FirstOrDefault<RelationTypeDto>("WHERE alias=@alias", new { alias = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias });
if (exists == null)
var relationTypeCount = Context.Database.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoRelationType WHERE alias=@alias",
new { alias = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias });
if (relationTypeCount > 0)
return;
var uniqueId = (Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias + "____" + Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteName).ToGuid();
Insert.IntoTable("umbracoRelationType").Row(new
{
var uniqueId = (Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias + "____" + Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteName).ToGuid();
Insert.IntoTable("umbracoRelationType").Row(new
{
typeUniqueId = uniqueId,
alias = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias,
name = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteName,
childObjectType = Constants.ObjectTypes.MediaType,
parentObjectType = Constants.ObjectTypes.MediaType,
dual = false
typeUniqueId = uniqueId,
alias = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias,
name = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteName,
childObjectType = Constants.ObjectTypes.MediaType,
parentObjectType = Constants.ObjectTypes.MediaType,
dual = false
}).Do();
}
}
}

View File

@@ -1,5 +1,6 @@
using System.Linq;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Migrations.Upgrade.V_7_12_0
{
@@ -11,16 +12,16 @@ namespace Umbraco.Core.Migrations.Upgrade.V_7_12_0
public override void Migrate()
{
var dbIndexes = SqlSyntax.GetDefinedIndexes(Context.Database)
.Select(x => new DbIndexDefinition
{
TableName = x.Item1,
IndexName = x.Item2,
ColumnName = x.Item3,
IsUnique = x.Item4
}).ToArray();
// Some people seem to have a constraint in their DB instead of an index, we'd need to drop that one
// See: https://our.umbraco.com/forum/using-umbraco-and-getting-started/93282-upgrade-from-711-to-712-fails
var constraints = SqlSyntax.GetConstraintsPerTable(Context.Database).Distinct().ToArray();
if (constraints.Any(x => x.Item2.InvariantEquals("IX_umbracoLanguage_languageISOCode")))
{
Delete.UniqueConstraint("IX_umbracoLanguage_languageISOCode").FromTable("umbracoLanguage").Do();
}
//Ensure the index exists before dropping it
//Now check for indexes of that name and drop that if it exists
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoLanguage_languageISOCode")))
{
Delete.Index("IX_umbracoLanguage_languageISOCode").OnTable("umbracoLanguage").Do();
@@ -35,8 +36,11 @@ namespace Umbraco.Core.Migrations.Upgrade.V_7_12_0
Create.Index("IX_umbracoLanguage_languageISOCode")
.OnTable("umbracoLanguage")
.OnColumn("languageISOCode")
.Ascending()
.WithOptions()
.Unique()
.Do();
}
}
}

View File

@@ -37,7 +37,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
var keyName = c.Item3.ToLowerInvariant();
if (dups.Contains(keyName))
{
Logger.Warn<RefactorXmlColumns>(() => $"Duplicate constraint {c.Item3}");
Logger.Warn<RefactorXmlColumns>("Duplicate constraint '{Constraint}'", c.Item3);
continue;
}
dups.Add(keyName);

View File

@@ -32,6 +32,7 @@ namespace Umbraco.Core.Models
/// <param name="name">Name of the content</param>
/// <param name="parent">Parent <see cref="IContent"/> object</param>
/// <param name="contentType">ContentType for the current Content object</param>
/// <param name="culture">An optional culture.</param>
public Content(string name, IContent parent, IContentType contentType, string culture = null)
: this(name, parent, contentType, new PropertyCollection(), culture)
{ }
@@ -43,6 +44,7 @@ namespace Umbraco.Core.Models
/// <param name="parent">Parent <see cref="IContent"/> object</param>
/// <param name="contentType">ContentType for the current Content object</param>
/// <param name="properties">Collection of properties</param>
/// <param name="culture">An optional culture.</param>
public Content(string name, IContent parent, IContentType contentType, PropertyCollection properties, string culture = null)
: base(name, parent, contentType, properties, culture)
{
@@ -57,6 +59,7 @@ namespace Umbraco.Core.Models
/// <param name="name">Name of the content</param>
/// <param name="parentId">Id of the Parent content</param>
/// <param name="contentType">ContentType for the current Content object</param>
/// <param name="culture">An optional culture.</param>
public Content(string name, int parentId, IContentType contentType, string culture = null)
: this(name, parentId, contentType, new PropertyCollection(), culture)
{ }
@@ -68,6 +71,7 @@ namespace Umbraco.Core.Models
/// <param name="parentId">Id of the Parent content</param>
/// <param name="contentType">ContentType for the current Content object</param>
/// <param name="properties">Collection of properties</param>
/// <param name="culture">An optional culture.</param>
public Content(string name, int parentId, IContentType contentType, PropertyCollection properties, string culture = null)
: base(name, parentId, contentType, properties, culture)
{
@@ -213,23 +217,23 @@ namespace Umbraco.Core.Models
[IgnoreDataMember]
public IEnumerable<string> PublishedCultures => _publishInfos?.Keys ?? Enumerable.Empty<string>();
//fixme should this return false if ID == 0?
//fixme should this return false if IsCultureAvailable(culture) is false?
/// <inheritdoc />
public bool IsCulturePublished(string culture)
// just check _publishInfos
// a non-available culture could not become published anyways
=> _publishInfos != null && _publishInfos.ContainsKey(culture);
//fixme should this return false if ID == 0?
//fixme should this return false if IsCultureAvailable(culture) is false?
/// <inheritdoc />
public bool WasCulturePublished(string culture)
// just check _publishInfosOrig - a copy of _publishInfos
// a non-available culture could not become published anyways
=> _publishInfosOrig != null && _publishInfosOrig.ContainsKey(culture);
//fixme should this return false if ID == 0?
//fixme should this return false if IsCultureAvailable(culture) is false?
/// <inheritdoc />
public bool IsCultureEdited(string culture)
=> !IsCulturePublished(culture) || (_editedCultures != null && _editedCultures.Contains(culture));
=> IsCultureAvailable(culture) && // is available, and
(!IsCulturePublished(culture) || // is not published, or
(_editedCultures != null && _editedCultures.Contains(culture))); // is edited
/// <inheritdoc/>
[IgnoreDataMember]

View File

@@ -87,6 +87,8 @@ namespace Umbraco.Core.Models
/// <para>A culture becomes published whenever values for this culture are published,
/// and the content published name for this culture is non-null. It becomes non-published
/// whenever values for this culture are unpublished.</para>
/// <para>A culture becomes published as soon as PublishCulture has been invoked,
/// even though the document might now have been saved yet (and can have no identity).</para>
/// </remarks>
bool IsCulturePublished(string culture);
@@ -107,8 +109,9 @@ namespace Umbraco.Core.Models
/// Gets a value indicated whether a given culture is edited.
/// </summary>
/// <remarks>
/// <para>A culture is edited when it is not published, or when it is published but
/// it has changes.</para>
/// <para>A culture is edited when it is available, and not published or published but
/// with changes.</para>
/// <para>A culture can be edited even though the document might now have been saved yet (and can have no identity).</para>
/// </remarks>
bool IsCultureEdited(string culture);

View File

@@ -41,7 +41,7 @@ namespace Umbraco.Core.Models
}
catch (Exception ex)
{
logger.Error<ImageCropperValueConverter>("Could not parse the string " + jsonString + " to a json object", ex);
logger.Error<ImageCropperValueConverter>(ex, "Could not parse the string '{JsonString}' to a json object", jsonString);
return string.Empty;
}
}

View File

@@ -552,9 +552,14 @@ namespace Umbraco.Core.Models
private Attempt<T> WarnIfPropertyTypeNotFoundOnGet<T>(string propertyAlias, string propertyName, T defaultVal)
{
void DoLog(string logPropertyAlias, string logPropertyName)
=> Current.Logger.Warn<Member>($"Trying to access the '{logPropertyName}' property on " + typeof(Member)
+ $" but the {logPropertyAlias} property does not exist on the member type so a default value is returned. Ensure that you have a property type with alias: "
+ logPropertyAlias + $" configured on your member type in order to use the '{logPropertyName}' property on the model correctly.");
{
Current.Logger.Warn<Member>("Trying to access the '{PropertyName}' property on '{MemberType}' " +
"but the {PropertyAlias} property does not exist on the member type so a default value is returned. " +
"Ensure that you have a property type with alias: {PropertyAlias} configured on your member type in order to use the '{PropertyName}' property on the model correctly.",
logPropertyName,
typeof(Member),
logPropertyAlias);
}
// if the property doesn't exist,
if (Properties.Contains(propertyAlias) == false)
@@ -572,8 +577,13 @@ namespace Umbraco.Core.Models
private bool WarnIfPropertyTypeNotFoundOnSet(string propertyAlias, string propertyName)
{
void DoLog(string logPropertyAlias, string logPropertyName)
=> Current.Logger.Warn<Member>($"An attempt was made to set a value on the property '{logPropertyName}' on type " + typeof(Member)
+ $" but the property type {logPropertyAlias} does not exist on the member type, ensure that this property type exists so that setting this property works correctly.");
{
Current.Logger.Warn<Member>("An attempt was made to set a value on the property '{PropertyName}' on type '{MemberType}' but the " +
"property type {PropertyAlias} does not exist on the member type, ensure that this property type exists so that setting this property works correctly.",
logPropertyName,
typeof(Member),
logPropertyAlias);
}
// if the property doesn't exist,
if (Properties.Contains(propertyAlias) == false)

View File

@@ -88,7 +88,7 @@ namespace Umbraco.Core.Models
if (entity.ValidatePath() == false)
{
logger.Warn(typeof(PathValidationExtensions), $"The content item {entity.Id} has an invalid path: {entity.Path} with parentID: {entity.ParentId}");
logger.Warn(typeof(PathValidationExtensions), "The content item {EntityId} has an invalid path: {EntityPath} with parentID: {EntityParentId}", entity.Id, entity.Path, entity.ParentId);
if (entity.ParentId == -1)
{
entity.Path = string.Concat("-1,", entity.Id);
@@ -112,4 +112,4 @@ namespace Umbraco.Core.Models
}
}
}
}

View File

@@ -225,7 +225,7 @@ namespace Umbraco.Core.Models
}
catch (Exception ex)
{
Current.Logger.Warn(typeof(PropertyTagsExtensions), ex, "Could not automatically convert stored json value to an enumerable string");
Current.Logger.Warn(typeof(PropertyTagsExtensions), ex, "Could not automatically convert stored json value to an enumerable string '{Json}'", value.ToString());
}
break;

View File

@@ -192,7 +192,7 @@ namespace Umbraco.Core.Packaging
assemblyName.Name,
"' see error log for full details."));
assembliesWithErrors.Add(a);
Current.Logger.Error<PackageBinaryInspector>("An error occurred scanning package assemblies", ex);
Current.Logger.Error<PackageBinaryInspector>(ex, "An error occurred scanning package assembly '{AssemblyName}'", assemblyName.FullName);
}
}
}
@@ -236,7 +236,7 @@ namespace Umbraco.Core.Packaging
a.GetName().Name,
"' see error log for full details."));
assembliesWithErrors.Add(a);
Current.Logger.Error<PackageBinaryInspector>("An error occurred scanning package assemblies", ex);
Current.Logger.Error<PackageBinaryInspector>(ex, "An error occurred scanning package assembly '{AssemblyName}'", a.GetName().FullName);
}
}

View File

@@ -6,13 +6,13 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
{
public ConstraintDefinition(ConstraintType type)
{
constraintType = type;
_constraintType = type;
}
private ConstraintType constraintType;
public bool IsPrimaryKeyConstraint { get { return ConstraintType.PrimaryKey == constraintType; } }
public bool IsUniqueConstraint { get { return ConstraintType.Unique == constraintType; } }
public bool IsNonUniqueConstraint { get { return ConstraintType.NonUnique == constraintType; } }
private readonly ConstraintType _constraintType;
public bool IsPrimaryKeyConstraint => ConstraintType.PrimaryKey == _constraintType;
public bool IsUniqueConstraint => ConstraintType.Unique == _constraintType;
public bool IsNonUniqueConstraint => ConstraintType.NonUnique == _constraintType;
public string SchemaName { get; set; }
public string ConstraintName { get; set; }

View File

@@ -1,13 +1,23 @@
namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
using System;
namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
{
/// <summary>
/// Represents a database index definition retreived by querying the database
/// </summary>
internal class DbIndexDefinition
{
public virtual string IndexName { get; set; }
public virtual string TableName { get; set; }
public virtual string ColumnName { get; set; }
public virtual bool IsUnique { get; set; }
public DbIndexDefinition(Tuple<string, string, string, bool> data)
{
TableName = data.Item1;
IndexName = data.Item2;
ColumnName = data.Item3;
IsUnique = data.Item4;
}
public string IndexName { get; }
public string TableName { get; }
public string ColumnName { get; }
public bool IsUnique { get; }
}
}

View File

@@ -487,10 +487,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (result.ContainsKey(temp.VersionId))
{
var msg = $"The query returned multiple property sets for content {temp.Id}, {temp.ContentType.Name}";
if (ContentRepositoryBase.ThrowOnWarning)
throw new InvalidOperationException(msg);
Logger.Warn<ContentRepositoryBase<TId, TEntity, TRepository>>(msg);
throw new InvalidOperationException($"The query returned multiple property sets for content {temp.Id}, {temp.ContentType.Name}");
Logger.Warn<ContentRepositoryBase<TId, TEntity, TRepository>>("The query returned multiple property sets for content {ContentId}, {ContentTypeName}", temp.Id, temp.ContentType.Name);
}
result[temp.VersionId] = new PropertyCollection(properties);

View File

@@ -227,10 +227,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
if (string.IsNullOrWhiteSpace(entity.Alias))
{
var m = $"ContentType '{entity.Name}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.";
var e = new Exception(m);
Logger.Error<ContentTypeRepository>(m, e);
throw e;
var ex = new Exception($"ContentType '{entity.Name}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.");
Logger.Error<ContentTypeRepository>("ContentType '{EntityName}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.", entity.Name);
throw ex;
}
((ContentType)entity).AddingEntity();

View File

@@ -521,10 +521,12 @@ AND umbracoNode.id <> @id",
{
if (string.IsNullOrWhiteSpace(pt.Alias))
{
var m = $"Property Type '{pt.Name}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.";
var e = new InvalidOperationException(m);
Logger.Error<ContentTypeRepositoryBase<TEntity>>(m, e);
throw e;
var ex = new InvalidOperationException($"Property Type '{pt.Name}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.");
Logger.Error<ContentTypeRepositoryBase<TEntity>>("Property Type '{PropertyTypeName}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.",
pt.Name);
throw ex;
}
}
@@ -532,10 +534,13 @@ AND umbracoNode.id <> @id",
{
if (string.IsNullOrWhiteSpace(entity.Alias))
{
var m = $"{typeof(TEntity).Name} '{entity.Name}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.";
var e = new InvalidOperationException(m);
Logger.Error<ContentTypeRepositoryBase<TEntity>>(m, e);
throw e;
var ex = new InvalidOperationException($"{typeof(TEntity).Name} '{entity.Name}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.");
Logger.Error<ContentTypeRepositoryBase<TEntity>>("{EntityTypeName} '{EntityName}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.",
typeof(TEntity).Name,
entity.Name);
throw ex;
}
}
@@ -561,7 +566,7 @@ AND umbracoNode.id <> @id",
}
else
{
Logger.Warn<ContentTypeRepositoryBase<TEntity>>(() => $"Could not assign a data type for the property type {propertyType.Alias} since no data type was found with a property editor {propertyType.PropertyEditorAlias}");
Logger.Warn<ContentTypeRepositoryBase<TEntity>>("Could not assign a data type for the property type {PropertyTypeAlias} since no data type was found with a property editor {PropertyEditorAlias}", propertyType.Alias, propertyType.PropertyEditorAlias);
}
}
}

View File

@@ -1073,7 +1073,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
NodeId = content.Id,
LanguageId = LanguageRepository.GetIdByIsoCode(culture) ?? throw new InvalidOperationException("Not a valid culture."),
Culture = culture,
Edited = !content.IsCulturePublished(culture) || (editedCultures != null && editedCultures.Contains(culture)) // if not published, always edited
// if not published, always edited
// no need to check for availability: it *is* available since it is in content.CultureNames
Edited = !content.IsCulturePublished(culture) || (editedCultures != null && editedCultures.Contains(culture))
};
}

View File

@@ -44,6 +44,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax
string TruncateTable { get; }
string CreateConstraint { get; }
string DeleteConstraint { get; }
[Obsolete("This is never used, use the Format(ForeignKeyDefinition) instead")]
string CreateForeignKeyConstraint { get; }
string DeleteDefaultConstraint { get; }
string FormatDateTime(DateTime date, bool includeTime = true);
@@ -80,8 +82,32 @@ namespace Umbraco.Core.Persistence.SqlSyntax
IEnumerable<string> GetTablesInSchema(IDatabase db);
IEnumerable<ColumnInfo> GetColumnsInSchema(IDatabase db);
/// <summary>
/// Returns all constraints defined in the database (Primary keys, foreign keys, unique constraints...) (does not include indexes)
/// </summary>
/// <param name="db"></param>
/// <returns>
/// A Tuple containing: TableName, ConstraintName
/// </returns>
IEnumerable<Tuple<string, string>> GetConstraintsPerTable(IDatabase db);
/// <summary>
/// Returns all constraints defined in the database (Primary keys, foreign keys, unique constraints...) (does not include indexes)
/// </summary>
/// <param name="db"></param>
/// <returns>
/// A Tuple containing: TableName, ColumnName, ConstraintName
/// </returns>
IEnumerable<Tuple<string, string, string>> GetConstraintsPerColumn(IDatabase db);
/// <summary>
/// Returns all defined Indexes in the database excluding primary keys
/// </summary>
/// <param name="db"></param>
/// <returns>
/// A Tuple containing: TableName, IndexName, ColumnName, IsUnique
/// </returns>
IEnumerable<Tuple<string, string, string, bool>> GetDefinedIndexes(IDatabase db);
}
}

View File

@@ -79,6 +79,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
return list;
}
/// <inheritdoc />
public override IEnumerable<Tuple<string, string>> GetConstraintsPerTable(IDatabase db)
{
List<Tuple<string, string>> list;
@@ -101,6 +102,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
return list;
}
/// <inheritdoc />
public override IEnumerable<Tuple<string, string, string>> GetConstraintsPerColumn(IDatabase db)
{
List<Tuple<string, string, string>> list;
@@ -127,6 +129,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
return list;
}
/// <inheritdoc />
public override IEnumerable<Tuple<string, string, string, bool>> GetDefinedIndexes(IDatabase db)
{
List<Tuple<string, string, string, bool>> list;
@@ -385,7 +388,7 @@ ORDER BY TABLE_NAME, INDEX_NAME",
}
catch (Exception ex)
{
_logger.Error<MySqlSyntaxProvider>("Error querying for lower_case support", ex);
_logger.Error<MySqlSyntaxProvider>(ex, "Error querying for lower_case support");
}
finally
{

View File

@@ -107,40 +107,27 @@ namespace Umbraco.Core.Persistence.SqlSyntax
item.IS_NULLABLE, item.DATA_TYPE)).ToList();
}
/// <inheritdoc />
public override IEnumerable<Tuple<string, string>> GetConstraintsPerTable(IDatabase db)
{
var items = db.Fetch<dynamic>("SELECT TABLE_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS");
var indexItems = db.Fetch<dynamic>("SELECT TABLE_NAME, INDEX_NAME FROM INFORMATION_SCHEMA.INDEXES");
return
items.Select(item => new Tuple<string, string>(item.TABLE_NAME, item.CONSTRAINT_NAME))
.Union(
indexItems.Select(
indexItem => new Tuple<string, string>(indexItem.TABLE_NAME, indexItem.INDEX_NAME)))
.ToList();
return items.Select(item => new Tuple<string, string>(item.TABLE_NAME, item.CONSTRAINT_NAME)).ToList();
}
/// <inheritdoc />
public override IEnumerable<Tuple<string, string, string>> GetConstraintsPerColumn(IDatabase db)
{
var items =
db.Fetch<dynamic>(
"SELECT CONSTRAINT_NAME, TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE");
var indexItems = db.Fetch<dynamic>("SELECT INDEX_NAME, TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.INDEXES");
return
items.Select(
item => new Tuple<string, string, string>(item.TABLE_NAME, item.COLUMN_NAME, item.CONSTRAINT_NAME))
.Union(
indexItems.Select(
indexItem =>
new Tuple<string, string, string>(indexItem.TABLE_NAME, indexItem.COLUMN_NAME,
indexItem.INDEX_NAME))).ToList();
var items = db.Fetch<dynamic>("SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE");
return items.Select(item => new Tuple<string, string, string>(item.TABLE_NAME, item.COLUMN_NAME, item.CONSTRAINT_NAME)).ToList();
}
/// <inheritdoc />
public override IEnumerable<Tuple<string, string, string, bool>> GetDefinedIndexes(IDatabase db)
{
var items =
db.Fetch<dynamic>(
@"SELECT TABLE_NAME, INDEX_NAME, COLUMN_NAME, [UNIQUE] FROM INFORMATION_SCHEMA.INDEXES
WHERE INDEX_NAME NOT LIKE 'PK_%'
WHERE PRIMARY_KEY=0
ORDER BY TABLE_NAME, INDEX_NAME");
return
items.Select(

View File

@@ -163,6 +163,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
item.IS_NULLABLE, item.DATA_TYPE)).ToList();
}
/// <inheritdoc />
public override IEnumerable<Tuple<string, string>> GetConstraintsPerTable(IDatabase db)
{
var items =
@@ -171,6 +172,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
return items.Select(item => new Tuple<string, string>(item.TABLE_NAME, item.CONSTRAINT_NAME)).ToList();
}
/// <inheritdoc />
public override IEnumerable<Tuple<string, string, string>> GetConstraintsPerColumn(IDatabase db)
{
var items =
@@ -179,6 +181,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
return items.Select(item => new Tuple<string, string, string>(item.TABLE_NAME, item.COLUMN_NAME, item.CONSTRAINT_NAME)).ToList();
}
/// <inheritdoc />
public override IEnumerable<Tuple<string, string, string, bool>> GetDefinedIndexes(IDatabase db)
{
var items =
@@ -188,7 +191,7 @@ CASE WHEN I.is_unique_constraint = 1 OR I.is_unique = 1 THEN 1 ELSE 0 END AS [U
from sys.tables as T inner join sys.indexes as I on T.[object_id] = I.[object_id]
inner join sys.index_columns as IC on IC.[object_id] = I.[object_id] and IC.[index_id] = I.[index_id]
inner join sys.all_columns as AC on IC.[object_id] = AC.[object_id] and IC.[column_id] = AC.[column_id]
WHERE I.name NOT LIKE 'PK_%'
WHERE I.is_primary_key = 0
order by T.name, I.name");
return items.Select(item => new Tuple<string, string, string, bool>(item.TABLE_NAME, item.INDEX_NAME, item.COLUMN_NAME,
item.UNIQUE == 1)).ToList();

View File

@@ -10,13 +10,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
public static IEnumerable<DbIndexDefinition> GetDefinedIndexesDefinitions(this ISqlSyntaxProvider sql, IDatabase db)
{
return sql.GetDefinedIndexes(db)
.Select(x => new DbIndexDefinition
{
TableName = x.Item1,
IndexName = x.Item2,
ColumnName = x.Item3,
IsUnique = x.Item4
}).ToArray();
.Select(x => new DbIndexDefinition(x)).ToArray();
}
/// <summary>

View File

@@ -190,13 +190,13 @@ namespace Umbraco.Core.Persistence
}
#endif
protected override void OnException(Exception x)
protected override void OnException(Exception ex)
{
_logger.Error<UmbracoDatabase>("Exception (" + InstanceId + ").", x);
_logger.Debug<UmbracoDatabase>(() => "At:\r\n" + Environment.StackTrace);
_logger.Error<UmbracoDatabase>(ex, "Exception ({InstanceId}).", InstanceId);
_logger.Debug<UmbracoDatabase>("At:\r\n{StackTrace}", Environment.StackTrace);
if (EnableSqlTrace == false)
_logger.Debug<UmbracoDatabase>(() => "Sql:\r\n" + CommandToString(LastSQL, LastArgs));
base.OnException(x);
_logger.Debug<UmbracoDatabase>("Sql:\r\n{Sql}", CommandToString(LastSQL, LastArgs));
base.OnException(ex);
}
private DbCommand _cmd;
@@ -208,7 +208,7 @@ namespace Umbraco.Core.Persistence
cmd.CommandTimeout = cmd.Connection.ConnectionTimeout;
if (EnableSqlTrace)
_logger.Debug<UmbracoDatabase>(() => CommandToString(cmd).Replace("{", "{{").Replace("}", "}}")); // fixme these escapes should be builtin
_logger.Debug<UmbracoDatabase>("SQL Trace:\r\n{Sql}", CommandToString(cmd).Replace("{", "{{").Replace("}", "}}")); // fixme these escapes should be builtin
#if DEBUG_DATABASES
// detects whether the command is already in use (eg still has an open reader...)

View File

@@ -261,7 +261,7 @@ namespace Umbraco.Core.PropertyEditors
var result = TryConvertValueToCrlType(editorValue.Value);
if (result.Success == false)
{
Current.Logger.Warn<DataValueEditor>(() => $"The value {editorValue.Value} cannot be converted to the type {ValueTypes.ToStorageType(ValueType)}");
Current.Logger.Warn<DataValueEditor>("The value {EditorValue} cannot be converted to the type {StorageTypeValue}", editorValue.Value, ValueTypes.ToStorageType(ValueType));
return null;
}
return result.Result;

View File

@@ -1,6 +1,4 @@
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
namespace Umbraco.Core.PropertyEditors
{
/// <summary>
/// Represents the configuration for the slider value editor.
@@ -8,7 +6,7 @@ namespace Umbraco.Web.PropertyEditors
public class SliderConfiguration
{
[ConfigurationField("enableRange", "Enable range", "boolean")]
public string Range { get; set; }
public bool EnableRange { get; set; }
[ConfigurationField("orientation", "Orientation", "views/propertyeditors/slider/orientation.prevalues.html")]
public string Orientation { get; set; }
@@ -38,7 +36,7 @@ namespace Umbraco.Web.PropertyEditors
public string Tooltip { get; set; }
[ConfigurationField("tooltipSplit", "Tooltip split", "boolean", Description = "If false show one tootip if true show two tooltips one for each handler")]
public string TooltipSplit { get; set; } // fixme bool?
public bool TooltipSplit { get; set; } // fixme bool?
[ConfigurationField("tooltipFormat", "Tooltip format", "textstring", Description = "The value wanted to be displayed in the tooltip. Use {0} and {1} for current values - {1} is only for range slider and if not using tooltip split.")]
public string TooltipFormat { get; set; }
@@ -47,7 +45,7 @@ namespace Umbraco.Web.PropertyEditors
public string TooltipPosition { get; set; }
[ConfigurationField("reversed", "Reversed", "boolean", Description = "Whether or not the slider should be reversed")]
public string Reversed { get; set; } // fixme bool?
public bool Reversed { get; set; } // fixme bool?
[ConfigurationField("ticks", "Ticks", "textstring", Description = "Comma-separated values. Used to define the values of ticks. Tick marks are indicators to denote special values in the range. This option overwrites min and max options.")]
public string Ticks { get; set; }
@@ -61,4 +59,4 @@ namespace Umbraco.Web.PropertyEditors
[ConfigurationField("ticksSnapBounds", "Ticks snap bounds", "number", Description = "Used to define the snap bounds of a tick. Snaps to the tick if value is within these bounds.")]
public int TicksSnapBounds { get; set; }
}
}
}

View File

@@ -1,10 +0,0 @@
using Newtonsoft.Json;
namespace Umbraco.Core.PropertyEditors
{
public class SliderPropertyEditorConfiguration
{
[JsonProperty("enableRange")]
public bool EnableRange { get; set; }
}
}

View File

@@ -100,7 +100,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
}
catch (Exception ex)
{
Current.Logger.Error<GridValueConverter>("Could not parse the string " + sourceString + " to a json object", ex);
Current.Logger.Error<GridValueConverter>(ex, "Could not parse the string '{JsonString}' to a json object", sourceString);
}
}

View File

@@ -43,7 +43,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
catch (Exception ex)
{
// cannot deserialize, assume it may be a raw image url
Current.Logger.Error<ImageCropperValueConverter>($"Could not deserialize string \"{sourceString}\" into an image cropper value.", ex);
Current.Logger.Error<ImageCropperValueConverter>(ex, "Could not deserialize string '{JsonString}' into an image cropper value.", sourceString);
value = new ImageCropperValue { Src = sourceString };
}

View File

@@ -57,7 +57,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
}
catch (Exception ex)
{
Current.Logger.Error<JsonValueConverter>("Could not parse the string " + sourceString + " to a json object", ex);
Current.Logger.Error<JsonValueConverter>(ex, "Could not parse the string '{JsonString}' to a json object", sourceString);
}
}

View File

@@ -72,7 +72,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return Storages.GetOrAdd(dataTypeId, id =>
{
var dataType = _dataTypeService.GetDataType(id);
var configuration = dataType.ConfigurationAs<SliderPropertyEditorConfiguration>();
var configuration = dataType.ConfigurationAs<SliderConfiguration>();
return configuration.EnableRange;
});
}

View File

@@ -35,7 +35,7 @@ namespace Umbraco.Core.Publishing
var counter = 0;
var contentForRelease = _contentService.GetContentForRelease().ToArray();
if (contentForRelease.Length > 0)
_logger.Debug<ScheduledPublisher>(() => $"There's {contentForRelease.Length} item(s) of content to be published");
_logger.Debug<ScheduledPublisher>("There's {ContentItemsForRelease} item(s) of content to be published", contentForRelease.Length);
foreach (var d in contentForRelease)
{
try
@@ -43,26 +43,26 @@ namespace Umbraco.Core.Publishing
d.ReleaseDate = null;
d.PublishCulture(); // fixme variants?
var result = _contentService.SaveAndPublish(d, userId: _userService.GetProfileById(d.WriterId).Id);
_logger.Debug<ContentService>(() => $"Result of publish attempt: {result.Result}");
_logger.Debug<ContentService>("Result of publish attempt: {PublishResult}", result.Result);
if (result.Success == false)
{
_logger.Error<ScheduledPublisher>($"Error publishing node {d.Id}");
_logger.Error<ScheduledPublisher>(null, "Error publishing node {NodeId}", d.Id);
}
else
{
counter++;
}
}
catch (Exception ee)
catch (Exception ex)
{
_logger.Error<ScheduledPublisher>($"Error publishing node {d.Id}", ee);
_logger.Error<ScheduledPublisher>(ex, "Error publishing node {NodeId}", d.Id);
throw;
}
}
var contentForExpiration = _contentService.GetContentForExpiration().ToArray();
if (contentForExpiration.Length > 0)
_logger.Debug<ScheduledPublisher>(() => $"There's {contentForExpiration.Length} item(s) of content to be unpublished");
_logger.Debug<ScheduledPublisher>("There's {ContentItemsForExpiration} item(s) of content to be unpublished", contentForExpiration.Length);
foreach (var d in contentForExpiration)
{
try
@@ -74,9 +74,9 @@ namespace Umbraco.Core.Publishing
counter++;
}
}
catch (Exception ee)
catch (Exception ex)
{
_logger.Error<ScheduledPublisher>($"Error unpublishing node {d.Id}", ee);
_logger.Error<ScheduledPublisher>(ex, "Error unpublishing node {NodeId}", d.Id);
throw;
}
}

View File

@@ -83,7 +83,7 @@ namespace Umbraco.Core.Runtime
try
{
Logger.Debug<CoreRuntime>(() => $"Runtime: {GetType().FullName}");
Logger.Debug<CoreRuntime>("Runtime: {Runtime}", GetType().FullName);
AquireMainDom(container);
DetermineRuntimeLevel(container);
@@ -141,11 +141,11 @@ namespace Umbraco.Core.Runtime
var dbfactory = container.GetInstance<IUmbracoDatabaseFactory>();
SetRuntimeStateLevel(dbfactory, Logger);
Logger.Debug<CoreRuntime>(() => $"Runtime level: {_state.Level}");
Logger.Debug<CoreRuntime>("Runtime level: {RuntimeLevel}", _state.Level);
if (_state.Level == RuntimeLevel.Upgrade)
{
Logger.Debug<CoreRuntime>(() => $"Configure database factory for upgrades.");
Logger.Debug<CoreRuntime>("Configure database factory for upgrades.");
dbfactory.ConfigureForUpgrade();
}
}
@@ -262,12 +262,12 @@ namespace Umbraco.Core.Runtime
{
// there *is* a local version, but it does not match the code version
// need to upgrade
logger.Debug<CoreRuntime>(() => $"Local version \"{localVersion}\" < code version \"{codeVersion}\", need to upgrade Umbraco.");
logger.Debug<CoreRuntime>("Local version '{LocalVersion}' < code version '{CodeVersion}', need to upgrade Umbraco.", localVersion, codeVersion);
_state.Level = RuntimeLevel.Upgrade;
}
else if (localVersion > codeVersion)
{
logger.Warn<CoreRuntime>(() => $"Local version \"{localVersion}\" > code version \"{codeVersion}\", downgrading is not supported.");
logger.Warn<CoreRuntime>("Local version '{LocalVersion}' > code version '{CodeVersion}', downgrading is not supported.", localVersion, codeVersion);
_state.Level = RuntimeLevel.BootFailed;
// in fact, this is bad enough that we want to throw
@@ -292,16 +292,14 @@ namespace Umbraco.Core.Runtime
{
connect = databaseFactory.CanConnect;
if (connect) break;
logger.Debug<CoreRuntime>(() => i == 0
? "Could not immediately connect to database, trying again."
: "Could not connect to database.");
logger.Debug<CoreRuntime>("Could not immediately connect to database, trying again.");
Thread.Sleep(1000);
}
if (connect == false)
{
// cannot connect to configured database, this is bad, fail
logger.Debug<CoreRuntime>(() => "Could not connect to database.");
logger.Debug<CoreRuntime>("Could not connect to database.");
_state.Level = RuntimeLevel.BootFailed;
// in fact, this is bad enough that we want to throw
@@ -365,7 +363,7 @@ namespace Umbraco.Core.Runtime
_state.CurrentMigrationState = state;
_state.FinalMigrationState = umbracoPlan.FinalState;
logger.Debug<CoreRuntime>(() => $"Final upgrade state is \"{_state.FinalMigrationState}\", database contains \"{state ?? "<null>"}\".");
logger.Debug<CoreRuntime>("Final upgrade state is '{FinalMigrationState}', database contains {DatabaseState}", _state.FinalMigrationState, state ?? "<null>");
return state == _state.FinalMigrationState;
}

View File

@@ -117,7 +117,7 @@ namespace Umbraco.Core
var change = url != null && !_applicationUrls.Contains(url);
if (change)
{
_logger.Info(typeof(ApplicationUrlHelper), $"New url \"{url}\" detected, re-discovering application url.");
_logger.Info(typeof(ApplicationUrlHelper), "New url '{Url}' detected, re-discovering application url.", url);
_applicationUrls.Add(url);
}

View File

@@ -318,7 +318,8 @@ namespace Umbraco.Core.Scoping
if (completed.HasValue == false || completed.Value == false)
{
if (LogUncompletedScopes)
_logger.Debug<Scope>(() => "Uncompleted Child Scope at\r\n" + Environment.StackTrace);
_logger.Debug<Scope>("Uncompleted Child Scope at\r\n {StackTrace}", Environment.StackTrace);
_completed = false;
}
}

View File

@@ -117,7 +117,7 @@ namespace Umbraco.Core.Scoping
}
// hard to inject into a static method :(
Current.Logger.Warn<ScopeProvider>(() => $"Missed {typeof(T).Name} Object {objectKey.ToString("N").Substring(0, 8)}");
Current.Logger.Warn<ScopeProvider>("Missed {TypeName} Object {ObjectKey}", typeof(T).Name, objectKey.ToString("N").Substring(0, 8));
#if DEBUG_SCOPES
//Current.Logger.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
#endif

View File

@@ -281,7 +281,7 @@ namespace Umbraco.Core.Security
if ((PasswordFormat == MembershipPasswordFormat.Hashed) && EnablePasswordRetrieval)
{
var ex = new ProviderException("Provider can not retrieve a hashed password");
Current.Logger.Error<MembershipProviderBase>("Cannot specify a Hashed password format with the enabledPasswordRetrieval option set to true", ex);
Current.Logger.Error<MembershipProviderBase>(ex, "Cannot specify a Hashed password format with the enabledPasswordRetrieval option set to true");
throw ex;
}

View File

@@ -1240,11 +1240,11 @@ namespace Umbraco.Core.Services.Implement
d.PublishCulture(); // fixme variants?
result = SaveAndPublish(d, userId: d.WriterId);
if (result.Success == false)
Logger.Error<ContentService>($"Failed to publish document id={d.Id}, reason={result.Result}.");
Logger.Error<ContentService>(null, "Failed to publish document id={DocumentId}, reason={Reason}.", d.Id, result.Result);
}
catch (Exception e)
{
Logger.Error<ContentService>($"Failed to publish document id={d.Id}, an exception was thrown.", e);
Logger.Error<ContentService>(e, "Failed to publish document id={DocumentId}, an exception was thrown.", d.Id);
throw;
}
yield return result;
@@ -1256,11 +1256,11 @@ namespace Umbraco.Core.Services.Implement
d.ExpireDate = null;
var result = Unpublish(d, userId: d.WriterId);
if (result.Success == false)
Logger.Error<ContentService>($"Failed to unpublish document id={d.Id}, reason={result.Result}.");
Logger.Error<ContentService>(null, "Failed to unpublish document id={DocumentId}, reason={Reason}.", d.Id, result.Result);
}
catch (Exception e)
{
Logger.Error<ContentService>($"Failed to unpublish document id={d.Id}, an exception was thrown.", e);
Logger.Error<ContentService>(e, "Failed to unpublish document id={DocumentId}, an exception was thrown.", d.Id);
throw;
}
}
@@ -1439,7 +1439,7 @@ namespace Umbraco.Core.Services.Implement
// fixme not going to work, do it differently
_mediaFileSystem.DeleteFiles(args.MediaFilesToDelete, // remove flagged files
(file, e) => Logger.Error<ContentService>("An error occurred while deleting file attached to nodes: " + file, e));
(file, e) => Logger.Error<ContentService>(e, "An error occurred while deleting file attached to nodes: {File}", file));
}
}
@@ -2178,7 +2178,7 @@ namespace Umbraco.Core.Services.Implement
// raise Publishing event
if (scope.Events.DispatchCancelable(Publishing, this, new PublishEventArgs<IContent>(content, evtMsgs)))
{
Logger.Info<ContentService>(() => $"Document \"'{content.Name}\" (id={content.Id}) cannot be published: publishing was cancelled.");
Logger.Info<ContentService>("Document '{ContentName}' (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "publishing was cancelled");
return new PublishResult(PublishResultType.FailedCancelledByEvent, evtMsgs, content);
}
@@ -2186,7 +2186,7 @@ namespace Umbraco.Core.Services.Implement
// either because it is 'publishing' or because it already has a published version
if (((Content) content).PublishedState != PublishedState.Publishing && content.PublishedVersionId == 0)
{
Logger.Info<ContentService>(() => $"Document \"{content.Name}\" (id={content.Id}) cannot be published: document does not have published values.");
Logger.Info<ContentService>("Document '{ContentName}' (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "document does not have published values");
return new PublishResult(PublishResultType.FailedNoPublishedValues, evtMsgs, content);
}
@@ -2194,15 +2194,15 @@ namespace Umbraco.Core.Services.Implement
switch (content.Status)
{
case ContentStatus.Expired:
Logger.Info<ContentService>(() => $"Document \"{content.Name}\" (id={content.Id}) cannot be published: document has expired.");
Logger.Info<ContentService>("Document '{ContentName}' (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "document has expired");
return new PublishResult(PublishResultType.FailedHasExpired, evtMsgs, content);
case ContentStatus.AwaitingRelease:
Logger.Info<ContentService>(() => $"Document \"{content.Name}\" (id={content.Id}) cannot be published: document is awaiting release.");
Logger.Info<ContentService>("Document '{ContentName}' (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "document is awaiting release");
return new PublishResult(PublishResultType.FailedAwaitingRelease, evtMsgs, content);
case ContentStatus.Trashed:
Logger.Info<ContentService>(() => $"Document \"{content.Name}\" (id={content.Id}) cannot be published: document is trashed.");
Logger.Info<ContentService>("Document '{ContentName}' (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "document is trashed");
return new PublishResult(PublishResultType.FailedIsTrashed, evtMsgs, content);
}
@@ -2214,7 +2214,7 @@ namespace Umbraco.Core.Services.Implement
var pathIsOk = content.ParentId == Constants.System.Root || IsPathPublished(GetParent(content));
if (pathIsOk == false)
{
Logger.Info<ContentService>(() => $"Document \"{content.Name}\" (id={content.Id}) cannot be published: parent is not published.");
Logger.Info<ContentService>("Document '{ContentName}' (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "parent is not published");
return new PublishResult(PublishResultType.FailedPathNotPublished, evtMsgs, content);
}
@@ -2238,7 +2238,7 @@ namespace Umbraco.Core.Services.Implement
// change state to publishing
((Content) content).PublishedState = PublishedState.Publishing;
Logger.Info<ContentService>(() => $"Content \"{content.Name}\" (id={content.Id}) has been published.");
Logger.Info<ContentService>("Document '{ContentName}' (id={ContentId}) has been published.", content.Name, content.Id);
return result;
}
@@ -2248,7 +2248,7 @@ namespace Umbraco.Core.Services.Implement
// raise UnPublishing event
if (scope.Events.DispatchCancelable(UnPublishing, this, new PublishEventArgs<IContent>(content, evtMsgs)))
{
Logger.Info<ContentService>(() => $"Document \"{content.Name}\" (id={content.Id}) cannot be unpublished: unpublishing was cancelled.");
Logger.Info<ContentService>("Document '{ContentName}' (id={ContentId}) cannot be unpublished: unpublishing was cancelled.", content.Name, content.Id);
return new UnpublishResult(UnpublishResultType.FailedCancelledByEvent, evtMsgs, content);
}
@@ -2271,13 +2271,13 @@ namespace Umbraco.Core.Services.Implement
if (content.ReleaseDate.HasValue && content.ReleaseDate.Value <= DateTime.Now)
{
content.ReleaseDate = null;
Logger.Info<ContentService>(() => $"Document \"{content.Name}\" (id={content.Id}) had its release date removed, because it was unpublished.");
Logger.Info<ContentService>("Document '{ContentName}' (id={ContentId}) had its release date removed, because it was unpublished.", content.Name, content.Id);
}
// change state to unpublishing
((Content) content).PublishedState = PublishedState.Unpublishing;
Logger.Info<ContentService>(() => $"Document \"{content.Name}\" (id={content.Id}) has been unpublished.");
Logger.Info<ContentService>("Document '{ContentName}' (id={ContentId}) has been unpublished.", content.Name, content.Id);
return attempt;
}

View File

@@ -104,7 +104,7 @@ namespace Umbraco.Core.Services.Implement
{
if (xmlSource.ContainsKey(culture) == false)
{
_logger.Warn<LocalizedTextService>(() => $"The culture specified {culture} was not found in any configured sources for this service");
_logger.Warn<LocalizedTextService>("The culture specified {Culture} was not found in any configured sources for this service", culture);
return result;
}
@@ -124,7 +124,7 @@ namespace Umbraco.Core.Services.Implement
{
if (_dictionarySource.ContainsKey(culture) == false)
{
_logger.Warn<LocalizedTextService>(() => $"The culture specified {culture} was not found in any configured sources for this service");
_logger.Warn<LocalizedTextService>("The culture specified {Culture} was not found in any configured sources for this service", culture);
return result;
}
@@ -207,7 +207,7 @@ namespace Umbraco.Core.Services.Implement
{
if (_dictionarySource.ContainsKey(culture) == false)
{
_logger.Warn<LocalizedTextService>(() => $"The culture specified {culture} was not found in any configured sources for this service");
_logger.Warn<LocalizedTextService>("The culture specified {Culture} was not found in any configured sources for this service", culture);
return "[" + key + "]";
}
@@ -245,7 +245,7 @@ namespace Umbraco.Core.Services.Implement
{
if (xmlSource.ContainsKey(culture) == false)
{
_logger.Warn<LocalizedTextService>(() => $"The culture specified {culture} was not found in any configured sources for this service");
_logger.Warn<LocalizedTextService>("The culture specified {Culture} was not found in any configured sources for this service", culture);
return "[" + key + "]";
}

View File

@@ -88,7 +88,7 @@ namespace Umbraco.Core.Services.Implement
}
catch (CultureNotFoundException)
{
Current.Logger.Warn<LocalizedTextServiceFileSources>(() => $"The culture {cultureVal} found in the file {fileInfo.FullName} is not a valid culture");
Current.Logger.Warn<LocalizedTextServiceFileSources>("The culture {CultureValue} found in the file {CultureFile} is not a valid culture", cultureVal, fileInfo.FullName);
//If the culture in the file is invalid, we'll just hope the file name is a valid culture below, otherwise
// an exception will be thrown.
}
@@ -125,7 +125,7 @@ namespace Umbraco.Core.Services.Implement
if (fileSourceFolder.Exists == false)
{
Current.Logger.Warn<LocalizedTextServiceFileSources>(() => $"The folder does not exist: {fileSourceFolder.FullName}, therefore no sources will be discovered");
Current.Logger.Warn<LocalizedTextServiceFileSources>("The folder does not exist: {FileSourceFolder}, therefore no sources will be discovered", fileSourceFolder.FullName);
}
else
{
@@ -204,7 +204,7 @@ namespace Umbraco.Core.Services.Implement
}
catch (Exception ex)
{
_logger.Error<LocalizedTextServiceFileSources>("Could not load file into XML " + supplementaryFile.File.FullName, ex);
_logger.Error<LocalizedTextServiceFileSources>(ex, "Could not load file into XML {File}", supplementaryFile.File.FullName);
continue;
}

View File

@@ -892,7 +892,7 @@ namespace Umbraco.Core.Services.Implement
scope.Events.Dispatch(Deleted, this, args);
_mediaFileSystem.DeleteFiles(args.MediaFilesToDelete, // remove flagged files
(file, e) => Logger.Error<MediaService>("An error occurred while deleting file attached to nodes: " + file, e));
(file, e) => Logger.Error<MediaService>(e, "An error occurred while deleting file attached to nodes: {File}", file));
}
}

View File

@@ -930,7 +930,7 @@ namespace Umbraco.Core.Services.Implement
// fixme - this is MOOT because the event will not trigger immediately
// it's been refactored already (think it's the dispatcher that deals with it?)
_mediaFileSystem.DeleteFiles(args.MediaFilesToDelete, // remove flagged files
(file, e) => Logger.Error<MemberService>("An error occurred while deleting file attached to nodes: " + file, e));
(file, e) => Logger.Error<MemberService>(e, "An error occurred while deleting file attached to nodes: {File}", file));
}
#endregion

View File

@@ -629,11 +629,11 @@ namespace Umbraco.Core.Services.Implement
try
{
if (Sendmail != null) Sendmail(s, request.Mail, _logger); else s.Send(request.Mail);
_logger.Debug<NotificationService>(() => string.Format("Notification \"{0}\" sent to {1} ({2})", request.Action, request.UserName, request.Email));
_logger.Debug<NotificationService>("Notification '{Action}' sent to {Username} ({Email})", request.Action, request.UserName, request.Email);
}
catch (Exception ex)
{
_logger.Error<NotificationService>("An error occurred sending notification", ex);
_logger.Error<NotificationService>(ex, "An error occurred sending notification");
s.Dispose();
s = new SmtpClient();
}

View File

@@ -491,7 +491,7 @@ namespace Umbraco.Core.Services.Implement
var tryCreateFolder = _contentTypeService.CreateContainer(-1, rootFolder);
if (tryCreateFolder == false)
{
_logger.Error<PackagingService>("Could not create folder: " + rootFolder, tryCreateFolder.Exception);
_logger.Error<PackagingService>(tryCreateFolder.Exception, "Could not create folder: {FolderName}", rootFolder);
throw tryCreateFolder.Exception;
}
var rootFolderId = tryCreateFolder.Result.Entity.Id;
@@ -525,7 +525,7 @@ namespace Umbraco.Core.Services.Implement
var tryCreateFolder = _contentTypeService.CreateContainer(current.Id, folderName);
if (tryCreateFolder == false)
{
_logger.Error<PackagingService>("Could not create folder: " + folderName, tryCreateFolder.Exception);
_logger.Error<PackagingService>(tryCreateFolder.Exception, "Could not create folder: {FolderName}", folderName);
throw tryCreateFolder.Exception;
}
return _contentTypeService.GetContainer(tryCreateFolder.Result.Entity.Id);
@@ -631,7 +631,7 @@ namespace Umbraco.Core.Services.Implement
}
else
{
_logger.Warn<PackagingService>(() => $"Packager: Error handling allowed templates. Template with alias '{alias}' could not be found.");
_logger.Warn<PackagingService>("Packager: Error handling allowed templates. Template with alias '{TemplateAlias}' could not be found.", alias);
}
}
@@ -647,7 +647,7 @@ namespace Umbraco.Core.Services.Implement
}
else
{
_logger.Warn<PackagingService>(() => $"Packager: Error handling default template. Default template with alias '{defaultTemplateElement.Value}' could not be found.");
_logger.Warn<PackagingService>("Packager: Error handling default template. Default template with alias '{DefaultTemplateAlias}' could not be found.", defaultTemplateElement.Value);
}
}
}
@@ -718,7 +718,8 @@ namespace Umbraco.Core.Services.Implement
// This means that the property will not be created.
if (dataTypeDefinition == null)
{
_logger.Warn<PackagingService>(() => $"Packager: Error handling creation of PropertyType '{property.Element("Name").Value}'. Could not find DataTypeDefintion with unique id '{dataTypeDefinitionId}' nor one referencing the DataType with a property editor alias (or legacy control id) '{property.Element("Type").Value.Trim()}'. Did the package creator forget to package up custom datatypes? This property will be converted to a label/readonly editor if one exists.");
_logger.Warn<PackagingService>("Packager: Error handling creation of PropertyType '{PropertyType}'. Could not find DataTypeDefintion with unique id '{DataTypeDefinitionId}' nor one referencing the DataType with a property editor alias (or legacy control id) '{PropertyEditorAlias}'. Did the package creator forget to package up custom datatypes? This property will be converted to a label/readonly editor if one exists.",
property.Element("Name").Value, dataTypeDefinitionId, property.Element("Type").Value.Trim());
//convert to a label!
dataTypeDefinition = _dataTypeService.GetByEditorAlias(Constants.PropertyEditors.Aliases.NoEdit).FirstOrDefault();
@@ -762,7 +763,9 @@ namespace Umbraco.Core.Services.Implement
var allowedChild = _importedContentTypes.ContainsKey(alias) ? _importedContentTypes[alias] : _contentTypeService.Get(alias);
if (allowedChild == null)
{
_logger.Warn<PackagingService>(() => $"Packager: Error handling DocumentType structure. DocumentType with alias '{alias}' could not be found and was not added to the structure for '{contentType.Alias}'.");
_logger.Warn<PackagingService>(
"Packager: Error handling DocumentType structure. DocumentType with alias '{DoctypeAlias}' could not be found and was not added to the structure for '{DoctypeStructureAlias}'.",
alias, contentType.Alias);
continue;
}
@@ -946,7 +949,7 @@ namespace Umbraco.Core.Services.Implement
var tryCreateFolder = _dataTypeService.CreateContainer(-1, rootFolder);
if (tryCreateFolder == false)
{
_logger.Error<PackagingService>("Could not create folder: " + rootFolder, tryCreateFolder.Exception);
_logger.Error<PackagingService>(tryCreateFolder.Exception, "Could not create folder: {FolderName}", rootFolder);
throw tryCreateFolder.Exception;
}
current = _dataTypeService.GetContainer(tryCreateFolder.Result.Entity.Id);
@@ -979,7 +982,7 @@ namespace Umbraco.Core.Services.Implement
var tryCreateFolder = _dataTypeService.CreateContainer(current.Id, folderName);
if (tryCreateFolder == false)
{
_logger.Error<PackagingService>("Could not create folder: " + folderName, tryCreateFolder.Exception);
_logger.Error<PackagingService>(tryCreateFolder.Exception, "Could not create folder: {FolderName}", folderName);
throw tryCreateFolder.Exception;
}
return _dataTypeService.GetContainer(tryCreateFolder.Result.Entity.Id);
@@ -1526,7 +1529,10 @@ namespace Umbraco.Core.Services.Implement
else if (string.IsNullOrEmpty((string)elementCopy.Element("Master")) == false &&
templateElements.Any(x => (string)x.Element("Alias") == (string)elementCopy.Element("Master")) == false)
{
_logger.Info<PackagingService>(string.Format("Template '{0}' has an invalid Master '{1}', so the reference has been ignored.", (string)elementCopy.Element("Alias"), (string)elementCopy.Element("Master")));
_logger.Info<PackagingService>(
"Template '{TemplateAlias}' has an invalid Master '{TemplateMaster}', so the reference has been ignored.",
(string) elementCopy.Element("Alias"),
(string) elementCopy.Element("Master"));
}
graph.AddItem(TopoGraph.CreateNode((string) elementCopy.Element("Alias"), elementCopy, dependencies));

View File

@@ -39,14 +39,14 @@ namespace Umbraco.Core.Sync
if (string.IsNullOrWhiteSpace(umbracoApplicationUrl) == false)
{
umbracoApplicationUrl = umbracoApplicationUrl.TrimEnd('/');
logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: " + umbracoApplicationUrl + " (provider)");
logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: {UmbracoAppUrl} (provider)", umbracoApplicationUrl);
return umbracoApplicationUrl;
}
if (request == null) return null;
umbracoApplicationUrl = GetApplicationUrlFromCurrentRequest(request, globalSettings);
logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: " + umbracoApplicationUrl + " (UmbracoModule request)");
logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: {UmbracoAppUrl} (UmbracoModule request)", umbracoApplicationUrl);
return umbracoApplicationUrl;
}
@@ -62,7 +62,7 @@ namespace Umbraco.Core.Sync
if (url.IsNullOrWhiteSpace() == false)
{
var umbracoApplicationUrl = url.TrimEnd('/');
logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: " + umbracoApplicationUrl + " (using web.routing/@umbracoApplicationUrl)");
logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: {UmbracoAppUrl} (using web.routing/@umbracoApplicationUrl)", umbracoApplicationUrl);
return umbracoApplicationUrl;
}
@@ -78,7 +78,7 @@ namespace Umbraco.Core.Sync
var ssl = globalSettings.UseHttps ? "s" : "";
url = "http" + ssl + "://" + url;
var umbracoApplicationUrl = url.TrimEnd('/');
logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: " + umbracoApplicationUrl + " (using scheduledTasks/@baseUrl)");
logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: {UmbracoAppUrl} (using scheduledTasks/@baseUrl)", umbracoApplicationUrl);
return umbracoApplicationUrl;
}
@@ -92,7 +92,7 @@ namespace Umbraco.Core.Sync
if (url.IsNullOrWhiteSpace() == false)
{
var umbracoApplicationUrl = url.TrimEnd('/');
logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: " + umbracoApplicationUrl + " (IServerRegistrar)");
logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: {UmbracoAppUrl} (IServerRegistrar)", umbracoApplicationUrl);
return umbracoApplicationUrl;
}

View File

@@ -192,9 +192,11 @@ namespace Umbraco.Core.Sync
if (count > Options.MaxProcessingInstructionCount)
{
//too many instructions, proceed to cold boot
Logger.Warn<DatabaseServerMessenger>(() => $"The instruction count ({count}) exceeds the specified MaxProcessingInstructionCount ({Options.MaxProcessingInstructionCount})."
Logger.Warn<DatabaseServerMessenger>(
"The instruction count ({InstructionCount}) exceeds the specified MaxProcessingInstructionCount ({MaxProcessingInstructionCount})."
+ " The server will skip existing instructions, rebuild its caches and indexes entirely, adjust its last synced Id"
+ " to the latest found in the database and maintain cache updates based on that Id.");
+ " to the latest found in the database and maintain cache updates based on that Id.",
count, Options.MaxProcessingInstructionCount);
coldboot = true;
}
@@ -350,7 +352,10 @@ namespace Umbraco.Core.Sync
}
catch (JsonException ex)
{
Logger.Error<DatabaseServerMessenger>($"Failed to deserialize instructions ({dto.Id}: \"{dto.Instructions}\").", ex);
Logger.Error<DatabaseServerMessenger>(ex, "Failed to deserialize instructions ({DtoId}: '{DtoInstructions}').",
dto.Id,
dto.Instructions);
lastId = dto.Id; // skip
continue;
}
@@ -406,7 +411,10 @@ namespace Umbraco.Core.Sync
catch (Exception ex)
{
Logger.Error<DatabaseServerMessenger>(
$"DISTRIBUTED CACHE IS NOT UPDATED. Failed to execute instructions ({dto.Id}: \"{dto.Instructions}\"). Instruction is being skipped/ignored", ex);
ex,
"DISTRIBUTED CACHE IS NOT UPDATED. Failed to execute instructions ({DtoId}: '{DtoInstructions}'). Instruction is being skipped/ignored",
dto.Id,
dto.Instructions);
//we cannot throw here because this invalid instruction will just keep getting processed over and over and errors
// will be thrown over and over. The only thing we can do is ignore and move on.

View File

@@ -157,7 +157,7 @@ namespace Umbraco.Core.Sync
{
if (refresher == null) throw new ArgumentNullException(nameof(refresher));
Current.Logger.Debug<ServerMessengerBase>(() => $"Invoking refresher {refresher.GetType()} on local server for message type RefreshByPayload");
Current.Logger.Debug<ServerMessengerBase>("Invoking refresher {RefresherType} on local server for message type RefreshByPayload", refresher.GetType());
var payloadRefresher = refresher as IPayloadCacheRefresher<TPayload>;
if (payloadRefresher == null)
@@ -179,7 +179,7 @@ namespace Umbraco.Core.Sync
{
if (refresher == null) throw new ArgumentNullException(nameof(refresher));
Current.Logger.Debug<ServerMessengerBase>(() => $"Invoking refresher {refresher.GetType()} on local server for message type {messageType}");
Current.Logger.Debug<ServerMessengerBase>("Invoking refresher {RefresherType} on local server for message type {MessageType}", refresher.GetType(), messageType);
switch (messageType)
{
@@ -240,7 +240,7 @@ namespace Umbraco.Core.Sync
{
if (refresher == null) throw new ArgumentNullException(nameof(refresher));
Current.Logger.Debug<ServerMessengerBase>(() => $"Invoking refresher {refresher.GetType()} on local server for message type {messageType}");
Current.Logger.Debug<ServerMessengerBase>("Invoking refresher {RefresherType} on local server for message type {MessageType}", refresher.GetType(), messageType);
var typedRefresher = refresher as ICacheRefresher<T>;

View File

@@ -64,8 +64,6 @@
<PackageReference Include="LightInject" Version="5.1.2" />
<PackageReference Include="LightInject.Annotation" Version="1.1.0" />
<PackageReference Include="LightInject.Web" Version="2.0.0" />
<PackageReference Include="log4net" Version="2.0.8" />
<PackageReference Include="Log4Net.Async" Version="2.0.4" />
<PackageReference Include="Microsoft.AspNet.Identity.Owin" Version="2.2.1" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.6" />
<PackageReference Include="Microsoft.Owin.Security.Cookies" Version="4.0.0" />
@@ -76,6 +74,27 @@
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="NPoco" Version="3.9.3" />
<PackageReference Include="Semver" Version="2.0.4" />
<PackageReference Include="Serilog">
<Version>2.7.1</Version>
</PackageReference>
<PackageReference Include="Serilog.Enrichers.Process">
<Version>2.0.1</Version>
</PackageReference>
<PackageReference Include="Serilog.Enrichers.Thread">
<Version>3.0.0</Version>
</PackageReference>
<PackageReference Include="Serilog.Filters.Expressions">
<Version>2.0.0</Version>
</PackageReference>
<PackageReference Include="Serilog.Formatting.Compact">
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="Serilog.Settings.AppSettings">
<Version>2.1.2</Version>
</PackageReference>
<PackageReference Include="Serilog.Sinks.File">
<Version>4.0.0</Version>
</PackageReference>
<PackageReference Include="Umbraco.SqlServerCE" Version="4.0.0.1" />
</ItemGroup>
<ItemGroup>
@@ -310,7 +329,8 @@
<Compile Include="IO\MediaPathSchemes\OriginalMediaPathScheme.cs" />
<Compile Include="IO\MediaPathSchemes\TwoGuidsMediaPathScheme.cs" />
<Compile Include="KeyValuePairExtensions.cs" />
<Compile Include="Logging\RollingFileCleanupAppender.cs" />
<Compile Include="Logging\SerilogExtensions\LoggerConfigExtensions.cs" />
<Compile Include="Logging\SerilogExtensions\Log4NetLevelMapperEnricher.cs" />
<Compile Include="Migrations\MigrationBase_Extra.cs" />
<Compile Include="Migrations\Upgrade\V_7_10_0\RenamePreviewFolder.cs" />
<Compile Include="Migrations\Upgrade\V_7_12_0\AddRelationTypeForMediaFolderOnDelete.cs" />
@@ -404,7 +424,7 @@
<Compile Include="PropertyEditors\PropertyEditorCollection.cs" />
<Compile Include="PropertyEditors\PropertyEditorTagsExtensions.cs" />
<Compile Include="PropertyEditors\PropertyValueLevel.cs" />
<Compile Include="PropertyEditors\SliderPropertyEditorConfiguration.cs" />
<Compile Include="PropertyEditors\SliderConfiguration.cs" />
<Compile Include="PropertyEditors\TagConfiguration.cs" />
<Compile Include="PropertyEditors\ValueConverters\ImageCropperValue.cs" />
<Compile Include="PropertyEditors\ValueConverters\ImageCropperValueTypeConverter.cs" />
@@ -455,7 +475,7 @@
<Compile Include="Dictionary\ICultureDictionary.cs" />
<Compile Include="Dictionary\ICultureDictionaryFactory.cs" />
<Compile Include="DisposableObject.cs" />
<Compile Include="DisposableTimer.cs" />
<Compile Include="Logging\DisposableTimer.cs" />
<Compile Include="EmailSender.cs" />
<Compile Include="Enum.cs" />
<Compile Include="EnumerableExtensions.cs" />
@@ -545,24 +565,18 @@
<Compile Include="IRuntimeState.cs" />
<Compile Include="LambdaExpressionCacheKey.cs" />
<Compile Include="ListExtensions.cs" />
<Compile Include="Logging\AppDomainTokenConverter.cs" />
<Compile Include="Logging\AsyncForwardingAppenderBase.cs" />
<Compile Include="Logging\DebugDiagnosticsLogger.cs" />
<Compile Include="Logging\ILogger.cs" />
<Compile Include="Logging\ImageProcessorLogger.cs" />
<Compile Include="Logging\IProfiler.cs" />
<Compile Include="Logging\IQueue.cs" />
<Compile Include="Logging\Logger.cs" />
<Compile Include="Logging\LoggerExtensions.cs" />
<Compile Include="Logging\LoggingEventContext.cs" />
<Compile Include="Logging\LoggingEventHelper.cs" />
<Compile Include="Logging\LoggingTaskExtension.cs" />
<Compile Include="Logging\LogProfiler.cs" />
<Compile Include="Logging\OwinLogger.cs" />
<Compile Include="Logging\OwinLoggerFactory.cs" />
<Compile Include="Logging\ProfilerExtensions.cs" />
<Compile Include="Logging\ProfilingLogger.cs" />
<Compile Include="Logging\RingBuffer.cs" />
<Compile Include="Logging\VoidProfiler.cs" />
<Compile Include="Logging\WebProfiler.cs" />
<Compile Include="Logging\WebProfilerComponent.cs" />

View File

@@ -3,10 +3,11 @@ using System.Reflection;
using System.Threading;
using System.Web;
using System.Web.Hosting;
using log4net;
using LightInject;
using Serilog;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
using ILogger = Umbraco.Core.Logging.ILogger;
namespace Umbraco.Core
{
@@ -27,7 +28,7 @@ namespace Umbraco.Core
/// </summary>
protected virtual ILogger GetLogger()
{
return Logger.CreateWithDefaultLog4NetConfiguration();
return Logger.CreateWithDefaultConfiguration();
}
// events - in the order they trigger
@@ -91,7 +92,7 @@ namespace Umbraco.Core
var msg = "Unhandled exception in AppDomain";
if (isTerminating) msg += " (terminating)";
msg += ".";
logger.Error<UmbracoApplicationBase>(msg, exception);
logger.Error<UmbracoApplicationBase>(exception, msg);
};
}
@@ -184,14 +185,15 @@ namespace Umbraco.Core
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField,
null, runtime, null);
var shutdownMsg = $"Application shutdown. Details: {HostingEnvironment.ShutdownReason}\r\n\r\n_shutDownMessage={shutDownMessage}\r\n\r\n_shutDownStack={shutDownStack}";
logger.Info<UmbracoApplicationBase>(shutdownMsg);
logger.Info<UmbracoApplicationBase>("Application shutdown. Details: {ShutdownReason}\r\n\r\n_shutDownMessage={ShutdownMessage}\r\n\r\n_shutDownStack={ShutdownStack}",
HostingEnvironment.ShutdownReason,
shutDownMessage,
shutDownStack);
}
catch (Exception)
{
//if for some reason that fails, then log the normal output
logger.Info<UmbracoApplicationBase>("Application shutdown. Reason: " + HostingEnvironment.ShutdownReason);
logger.Info<UmbracoApplicationBase>("Application shutdown. Reason: {ShutdownReason}", HostingEnvironment.ShutdownReason);
}
}
@@ -201,7 +203,10 @@ namespace Umbraco.Core
{
HandleApplicationEnd();
OnApplicationEnd(sender, evargs);
LogManager.Shutdown();
//Not sure if we need to do this - as my POC approach I never had to deal with this
//As the LightInject container when tearing down will dispose of Serilog AFAIK
Log.CloseAndFlush();
}
#endregion
@@ -220,7 +225,7 @@ namespace Umbraco.Core
// ignore HTTP errors
if (exception.GetType() == typeof(HttpException)) return;
Current.Logger.Error<UmbracoApplicationBase>("An unhandled exception occurred.", exception);
Current.Logger.Error<UmbracoApplicationBase>(exception, "An unhandled exception occurred");
}
// called by ASP.NET (auto event wireup) at any phase in the application life cycle
@@ -243,7 +248,7 @@ namespace Umbraco.Core
}
catch (Exception ex)
{
Current.Logger.Error<UmbracoApplicationBase>($"Error in {name} handler.", ex);
Current.Logger.Error<UmbracoApplicationBase>(ex, "Error in {Name} handler.", name);
throw;
}
}

View File

@@ -155,7 +155,7 @@ namespace Umbraco.Core
}
catch (ArgumentException ex)
{
Current.Logger.Error(typeof(UriExtensions), "Failed to determine if request was client side", ex);
Current.Logger.Error(typeof(UriExtensions), ex, "Failed to determine if request was client side");
return false;
}
}

View File

@@ -164,8 +164,6 @@ namespace Umbraco.Core.Xml.XPath
#pragma warning disable 168
var msg = string.Format(format, args); // unused if not writing, hence #pragma
#pragma warning restore 168
//LogHelper.Debug<MacroNavigator>(msg); // beware! this can quicky overflow log4net
//Console.WriteLine(msg);
}
#endif

View File

@@ -4,7 +4,7 @@
// In Debug configuration, diagnostics code can be enabled by defining DEBUGNAVIGATOR below,
// but by default nothing is writted, unless some lines are un-commented in Debug(...) below.
//
// Beware! Diagnostics are extremely verbose and can overflow log4net pretty easily.
// Beware! Diagnostics are extremely verbose and can overflow logging pretty easily.
#if DEBUG
// define to enable diagnostics code
@@ -254,8 +254,6 @@ namespace Umbraco.Core.Xml.XPath
//format = "[" + _uid.ToString("00000") + "] " + Tabs.Substring(0, _tabs) + format;
//var msg = string.Format(format, args);
//LogHelper.Debug<NavigableNavigator>(msg); // beware! this can quicky overflow log4net
//Console.WriteLine(msg);
}
#endif

View File

@@ -212,7 +212,7 @@ namespace Umbraco.Examine
var filtered = c.RawQuery(rawQuery);
var results = searcher.Search(filtered);
ProfilingLogger.Logger.Debug(GetType(), $"DeleteFromIndex with query: {rawQuery} (found {results.TotalItemCount} results)");
ProfilingLogger.Logger.Debug(GetType(), "DeleteFromIndex with query: {Query} (found {TotalItems} results)", rawQuery, results.TotalItemCount);
//need to queue a delete item for each one found
foreach (var r in results)

View File

@@ -162,7 +162,7 @@ namespace Umbraco.Examine
/// </remarks>
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
ProfilingLogger.Logger.Debug(GetType(), () => $"{name} indexer initializing");
ProfilingLogger.Logger.Debug(GetType(), "{IndexerName} indexer initializing", name);
if (config["enableDefaultEventHandler"] != null && bool.TryParse(config["enableDefaultEventHandler"], out var enabled))
{
@@ -331,11 +331,11 @@ namespace Umbraco.Examine
/// <summary>
/// overridden for logging
/// </summary>
/// <param name="e"></param>
protected override void OnIndexingError(IndexingErrorEventArgs e)
/// <param name="ex"></param>
protected override void OnIndexingError(IndexingErrorEventArgs ex)
{
ProfilingLogger.Logger.Error(GetType(), e.Message, e.InnerException);
base.OnIndexingError(e);
ProfilingLogger.Logger.Error(GetType(), ex.InnerException, ex.Message);
base.OnIndexingError(ex);
}
/// <summary>
@@ -359,7 +359,12 @@ namespace Umbraco.Examine
}
}
ProfilingLogger.Logger.Debug(GetType(), () => $"Write lucene doc id:{docArgs.ValueSet.Id}, category:{docArgs.ValueSet.Category}, type:{docArgs.ValueSet.ItemType}");
ProfilingLogger.Logger.Debug(GetType(),
"Write lucene doc id:{DocumentId}, category:{DocumentCategory}, type:{DocumentItemType}",
docArgs.ValueSet.Id,
docArgs.ValueSet.Category,
docArgs.ValueSet.ItemType);
base.OnDocumentWriting(docArgs);
}
@@ -369,7 +374,10 @@ namespace Umbraco.Examine
/// </summary>
protected override void AddDocument(Document doc, IndexItem item, IndexWriter writer)
{
ProfilingLogger.Logger.Debug(GetType(), () => $"AddDocument {item.ValueSet.Id} with type {item.ValueSet.ItemType}");
ProfilingLogger.Logger.Debug(GetType(),
"AddDocument {DocumentId} with type {DocumentItemType}",
item.ValueSet.Id,
item.ValueSet.ItemType);
base.AddDocument(doc, item, writer);
}

View File

@@ -61,7 +61,7 @@
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.10.13" />
<PackageReference Include="BenchmarkDotNet.Toolchains.Roslyn" Version="0.10.13" />
<PackageReference Include="Castle.Core" Version="4.2.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.8.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.9.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="2.8.0" />
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.11" />
<PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.0" />

View File

@@ -5,10 +5,6 @@
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-2.0.8.0" newVersion="2.0.8.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0"/>

View File

@@ -107,10 +107,6 @@
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-2.0.8.0" newVersion="2.0.8.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0"/>

View File

@@ -356,7 +356,6 @@ namespace Umbraco.Tests.Composing
"Dynamic,",
"HtmlDiff,",
"Iesi.Collections,",
"log4net,",
"Microsoft.",
"Newtonsoft.",
"NHibernate.",
@@ -379,7 +378,8 @@ namespace Umbraco.Tests.Composing
"ICSharpCode.",
"CookComputing.",
/* Mono */
"MonoDevelop.NUnit"
"MonoDevelop.NUnit",
"Serilog."
};
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>()

View File

@@ -14,7 +14,7 @@ namespace Umbraco.Tests.Persistence
{
[TestFixture]
[Timeout(60000)]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Logger = UmbracoTestOptions.Logger.Log4Net)]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Logger = UmbracoTestOptions.Logger.Serilog)]
public class LocksTests : TestWithDatabaseBase
{
protected override void Initialize()

View File

@@ -1,82 +1,93 @@
using System;
using System.Linq;
using Umbraco.Core.Logging;
namespace Umbraco.Tests.TestHelpers
{
public class ConsoleLogger : ILogger
{
public void Error(Type reporting, string message, Exception exception)
public void Fatal(Type reporting, Exception exception, string message)
{
Console.WriteLine("INFO {0} - {1}", reporting.Name, message);
Console.WriteLine("FATAL {0} - {1}", reporting.Name, message);
Console.WriteLine(exception);
}
public void Fatal(Type reporting, Exception exception)
{
Console.WriteLine("FATAL {0}", reporting.Name);
Console.WriteLine(exception);
}
public void Fatal(Type reporting, string message)
{
Console.WriteLine("FATAL {0} - {1}", reporting.Name, message);
}
public void Fatal(Type reporting, Exception exception, string format, params object[] args)
{
Console.WriteLine("FATAL {0} - {1}", reporting.Name, string.Format(format, args));
Console.WriteLine(exception);
}
public void Fatal(Type reporting, string format, params object[] args)
{
Console.WriteLine("FATAL {0} - {1}", reporting.Name, string.Format(format, args));
}
public void Error(Type reporting, Exception exception, string message)
{
Console.WriteLine("ERROR {0} - {1}", reporting.Name, message);
Console.WriteLine(exception);
}
public void Error(Type reporting, Exception exception)
{
Console.WriteLine("ERROR {0}", reporting.Name);
Console.WriteLine(exception);
}
public void Error(Type reporting, string message)
{
Console.WriteLine("ERROR {0} - {1}", reporting.Name, message);
}
public void Error(Type reporting, Exception exception, string format, params object[] args)
{
Console.WriteLine("ERROR {0} - {1}", reporting.Name, string.Format(format, args));
Console.WriteLine(exception);
}
public void Error(Type reporting, string format, params object[] args)
{
Console.WriteLine("ERROR {0} - {1}", reporting.Name, string.Format(format, args));
}
public void Warn(Type reporting, string message)
{
Console.WriteLine("WARN {0} - {1}", reporting.Name, message);
}
public void Warn(Type reporting, Func<string> messageBuilder)
{
Console.WriteLine("WARN {0} - {1}", reporting.Name, messageBuilder());
}
public void Warn(Type reporting, string format, params object[] args)
{
Console.WriteLine("WARN {0} - {1}", reporting.Name, string.Format(format, args));
}
public void Warn(Type reporting, string format, params Func<object>[] args)
{
Console.WriteLine("WARN {0} - {1}", reporting.Name, string.Format(format, args.Select(x => x()).ToArray()));
}
public void Warn(Type reporting, Exception exception, string message)
{
Console.WriteLine("WARN {0} - {1}", reporting.Name, message);
Console.WriteLine(exception);
}
public void Warn(Type reporting, Exception exception, Func<string> messageBuilder)
{
Console.WriteLine("WARN {0} - {1}", reporting.Name, messageBuilder());
Console.WriteLine(exception);
}
public void Warn(Type reporting, Exception exception, string format, params object[] args)
{
Console.WriteLine("WARN {0} - {1}", reporting.Name, string.Format(format, args));
Console.WriteLine(exception);
}
public void Warn(Type reporting, Exception exception, string format, params Func<object>[] args)
{
Console.WriteLine("WARN {0} - {1}", reporting.Name, string.Format(format, args.Select(x => x()).ToArray()));
Console.WriteLine(exception);
}
public void WarnWithException(Type reporting, string format, Exception e, params Func<object>[] args)
{
Console.WriteLine("WARN {0} - {1}", reporting.Name, string.Format(format, args.Select(x => x()).ToArray()));
Console.WriteLine(e);
}
public void Info(Type reporting, Func<string> generateMessage)
{
Console.WriteLine("INFO {0} - {1}", reporting.Name, generateMessage());
}
public void Info(Type reporting, string format, params object[] args)
{
Console.WriteLine("INFO {0} - {1}", reporting.Name, string.Format(format, args));
}
public void Info(Type reporting, string format, params Func<object>[] args)
{
Console.WriteLine("INFO {0} - {1}", reporting.Name, string.Format(format, args.Select(x => x()).ToArray()));
}
public void Info(Type reporting, string message)
{
Console.WriteLine("INFO {0} - {1}", reporting.Name, message);
@@ -87,19 +98,19 @@ namespace Umbraco.Tests.TestHelpers
Console.WriteLine("DEBUG {0} - {1}", reporting.Name, message);
}
public void Debug(Type reporting, Func<string> messageBuilder)
{
Console.WriteLine("DEBUG {0} - {1}", reporting.Name, messageBuilder());
}
public void Debug(Type reporting, string format, params object[] args)
{
Console.WriteLine("DEBUG {0} - {1}", reporting.Name, string.Format(format, args));
}
public void Debug(Type reporting, string format, params Func<object>[] args)
public void Verbose(Type reporting, string message)
{
Console.WriteLine("DEBUG {0} - {1}", reporting.Name, string.Format(format, args.Select(x => x()).ToArray()));
Console.WriteLine("VERBOSE {0} - {1}", reporting.Name, message);
}
public void Verbose(Type reporting, string format, params object[] args)
{
Console.WriteLine("VERBOSE {0} - {1}", reporting.Name, string.Format(format, args));
}
}
}

View File

@@ -344,7 +344,7 @@ namespace Umbraco.Tests.TestHelpers
}
catch (Exception ex)
{
Logger.Error<TestWithDatabaseBase>("Could not remove the old database file", ex);
Logger.Error<TestWithDatabaseBase>(ex, "Could not remove the old database file");
// swallow this exception - that's because a sub class might require further teardown logic
onFail?.Invoke(ex);

Some files were not shown because too many files have changed in this diff Show More