From 7f78aef05f103cfbea78527f99c4f7fb17640584 Mon Sep 17 00:00:00 2001 From: Anthony Dang Date: Thu, 20 Nov 2014 16:11:04 +0000 Subject: [PATCH 1/3] Issue U4-5231 - Created an interface based on the LogHelper, and created a service, exposed through Application.Services. --- src/Umbraco.Core/Logging/LogHelper.cs | 1 + src/Umbraco.Core/Services/ILoggingService.cs | 40 +++ src/Umbraco.Core/Services/LoggingService.cs | 267 +++++++++++++++++++ src/Umbraco.Core/Services/ServiceContext.cs | 20 +- src/Umbraco.Core/Umbraco.Core.csproj | 6 +- src/Umbraco.Tests/MockTests.cs | 5 +- 6 files changed, 332 insertions(+), 7 deletions(-) create mode 100644 src/Umbraco.Core/Services/ILoggingService.cs create mode 100644 src/Umbraco.Core/Services/LoggingService.cs diff --git a/src/Umbraco.Core/Logging/LogHelper.cs b/src/Umbraco.Core/Logging/LogHelper.cs index 9291ffec1d..0513699f4e 100644 --- a/src/Umbraco.Core/Logging/LogHelper.cs +++ b/src/Umbraco.Core/Logging/LogHelper.cs @@ -9,6 +9,7 @@ namespace Umbraco.Core.Logging /// /// Used for logging /// + [Obsolete("Use UmbracoContext.Current.Application.Services.LoggingService instead")] public static class LogHelper { /// diff --git a/src/Umbraco.Core/Services/ILoggingService.cs b/src/Umbraco.Core/Services/ILoggingService.cs new file mode 100644 index 0000000000..1094428c5e --- /dev/null +++ b/src/Umbraco.Core/Services/ILoggingService.cs @@ -0,0 +1,40 @@ +using System; + +namespace Umbraco.Core.Services +{ + /// + /// Interface for logging service. + /// + public interface ILoggingService + { + void Error(string message, Exception exception); + void Error(Type callingType, string message, Exception exception); + void Warn(Type callingType, string message, params Func[] formatItems); + void Warn(Type callingType, string message, bool showHttpTrace, params Func[] formatItems); + void WarnWithException(Type callingType, string message, Exception e, params Func[] formatItems); + void WarnWithException(Type callingType, string message, bool showHttpTrace, Exception e, params Func[] formatItems); + + void Warn(string message, params Func[] formatItems); + void Warn(string message, bool showHttpTrace, params Func[] formatItems); + void WarnWithException(string message, Exception e, params Func[] formatItems); + void WarnWithException(string message, bool showHttpTrace, Exception e, params Func[] formatItems); + + void Info(Func generateMessage); + + void Info(Type callingType, Func generateMessage); + + void Info(Type type, string generateMessageFormat, params Func[] formatItems); + + void Info(string generateMessageFormat, params Func[] formatItems); + + void Debug(Func generateMessage); + + void Debug(Type callingType, Func generateMessage); + + void Debug(Type type, string generateMessageFormat, params Func[] formatItems); + + void Debug(string generateMessageFormat, params Func[] formatItems); + + void Debug(string generateMessageFormat, bool showHttpTrace, params Func[] formatItems); + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Services/LoggingService.cs b/src/Umbraco.Core/Services/LoggingService.cs new file mode 100644 index 0000000000..7c6bbc8958 --- /dev/null +++ b/src/Umbraco.Core/Services/LoggingService.cs @@ -0,0 +1,267 @@ +using System; +using System.Linq; +using System.Threading; +using System.Web; +using log4net; + +namespace Umbraco.Core.Services +{ + /// + /// Used for logging + /// + public class LoggingService : ILoggingService + { + /// + /// Returns a logger for the type specified + /// + /// + /// + internal ILog LoggerFor() + { + return LogManager.GetLogger(typeof(T)); + } + + /// + /// Returns a logger for the object's type + /// + /// + /// + internal ILog LoggerFor(object getTypeFromInstance) + { + if (getTypeFromInstance == null) throw new ArgumentNullException("getTypeFromInstance"); + + return LogManager.GetLogger(getTypeFromInstance.GetType()); + } + + /// + /// Useful if the logger itself is running on another thread + /// + /// + /// + private string PrefixThreadId(string generateMessageFormat) + { + return "[Thread " + Thread.CurrentThread.ManagedThreadId + "] " + generateMessageFormat; + } + + #region Error + /// + /// Adds an error log + /// + /// + /// + /// + public void Error(string message, Exception exception) + { + Error(typeof (T), message, exception); + } + + public void Error(Type callingType, string message, Exception exception) + { + var logger = LogManager.GetLogger(callingType); + if (logger != null) + logger.Error(PrefixThreadId(message), exception); + } + + #endregion + + #region Warn + + public void Warn(Type callingType, string message, params Func[] formatItems) + { + var logger = LogManager.GetLogger(callingType); + if (logger == null || !logger.IsWarnEnabled) return; + logger.WarnFormat(PrefixThreadId(message), formatItems.Select(x => x.Invoke()).ToArray()); + } + + public void Warn(Type callingType, string message, bool showHttpTrace, params Func[] formatItems) + { + Mandate.ParameterNotNull(callingType, "callingType"); + Mandate.ParameterNotNullOrEmpty(message, "message"); + + if (showHttpTrace && HttpContext.Current != null) + { + HttpContext.Current.Trace.Warn(callingType.Name, string.Format(message, formatItems.Select(x => x.Invoke()).ToArray())); + } + + var logger = LogManager.GetLogger(callingType); + if (logger == null || !logger.IsWarnEnabled) return; + logger.WarnFormat(PrefixThreadId(message), formatItems.Select(x => x.Invoke()).ToArray()); + + } + + public void WarnWithException(Type callingType, string message, Exception e, params Func[] formatItems) + { + WarnWithException(callingType, message, false, e, formatItems); + } + + public void WarnWithException(Type callingType, string message, bool showHttpTrace, Exception e, params Func[] formatItems) + { + Mandate.ParameterNotNull(e, "e"); + Mandate.ParameterNotNull(callingType, "callingType"); + Mandate.ParameterNotNullOrEmpty(message, "message"); + + if (showHttpTrace && HttpContext.Current != null) + { + HttpContext.Current.Trace.Warn( + callingType.Name, + string.Format(message, formatItems.Select(x => x.Invoke()).ToArray()), + e); + } + + var logger = LogManager.GetLogger(callingType); + if (logger == null || !logger.IsWarnEnabled) return; + var executedParams = formatItems.Select(x => x.Invoke()).ToArray(); + logger.WarnFormat(PrefixThreadId(message) + ". Exception: " + e, executedParams); + } + + /// + /// Adds a warn log + /// + /// + /// + /// + public void Warn(string message, params Func[] formatItems) + { + Warn(typeof(T), message, formatItems); + } + + public void Warn(string message, bool showHttpTrace, params Func[] formatItems) + { + Warn(typeof(T), message, showHttpTrace, formatItems); + } + + public void WarnWithException(string message, Exception e, params Func[] formatItems) + { + WarnWithException(typeof(T), message, e, formatItems); + } + public void WarnWithException(string message, bool showHttpTrace, Exception e, params Func[] formatItems) + { + WarnWithException(typeof(T), message, showHttpTrace, e, formatItems); + } + + #endregion + + #region Info + /// + /// Traces a message, only generating the message if tracing is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled. + /// + /// + /// The delegate to generate a message. + /// + public void Info(Func generateMessage) + { + Info(typeof(T), generateMessage); + } + + /// + /// Traces if tracing is enabled. + /// + /// + /// + public void Info(Type callingType, Func generateMessage) + { + var logger = LogManager.GetLogger(callingType); + if (logger == null || !logger.IsInfoEnabled) return; + logger.Info(PrefixThreadId(generateMessage.Invoke())); + } + + /// + /// Traces if tracing is enabled. + /// + /// The type for the logging namespace. + /// The message format. + /// The format items. + public void Info(Type type, string generateMessageFormat, params Func[] formatItems) + { + var logger = LogManager.GetLogger(type); + if (logger == null || !logger.IsInfoEnabled) return; + var executedParams = formatItems.Select(x => x.Invoke()).ToArray(); + logger.InfoFormat(PrefixThreadId(generateMessageFormat), executedParams); + } + + /// + /// Traces a message, only generating the message if tracing is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled. + /// + /// + /// The generate message format. + /// The format items. + /// + public void Info(string generateMessageFormat, params Func[] formatItems) + { + Info(typeof(T), generateMessageFormat, formatItems); + } + #endregion + + #region Debug + /// + /// Debugs a message, only generating the message if tracing is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled. + /// + /// + /// The delegate to generate a message. + /// + public void Debug(Func generateMessage) + { + Debug(typeof(T), generateMessage); + } + + /// + /// Debugs if tracing is enabled. + /// + /// + /// + public void Debug(Type callingType, Func generateMessage) + { + var logger = LogManager.GetLogger(callingType); + if (logger == null || !logger.IsDebugEnabled) return; + logger.Debug(PrefixThreadId(generateMessage.Invoke())); + } + + /// + /// Debugs if tracing is enabled. + /// + /// The type for the logging namespace. + /// The message format. + /// The format items. + public void Debug(Type type, string generateMessageFormat, params Func[] formatItems) + { + var logger = LogManager.GetLogger(type); + if (logger == null || !logger.IsDebugEnabled) return; + var executedParams = formatItems.Select(x => x.Invoke()).ToArray(); + logger.DebugFormat(PrefixThreadId(generateMessageFormat), executedParams); + } + + /// + /// Debugs a message, only generating the message if debug is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled. + /// + /// + /// The generate message format. + /// The format items. + /// + public void Debug(string generateMessageFormat, params Func[] formatItems) + { + Debug(typeof(T), generateMessageFormat, formatItems); + } + + /// + /// Debugs a message and also writes to the TraceContext specified, useful for when you would like the debug + /// output also displayed in the Http trace output. + /// + /// + /// + /// + /// + public void Debug(string generateMessageFormat, bool showHttpTrace, params Func[] formatItems) + { + if (showHttpTrace && HttpContext.Current != null) + { + HttpContext.Current.Trace.Write( + typeof(T).Name, + string.Format(generateMessageFormat, formatItems.Select(x => x()).ToArray())); + } + Debug(typeof(T), generateMessageFormat, formatItems); + } + + #endregion + + } +} diff --git a/src/Umbraco.Core/Services/ServiceContext.cs b/src/Umbraco.Core/Services/ServiceContext.cs index a6e74b00d0..9de61bf7f0 100644 --- a/src/Umbraco.Core/Services/ServiceContext.cs +++ b/src/Umbraco.Core/Services/ServiceContext.cs @@ -1,4 +1,5 @@ using System; +using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.UnitOfWork; using Umbraco.Core.Publishing; @@ -12,6 +13,7 @@ namespace Umbraco.Core.Services /// public class ServiceContext { + private Lazy _loggingService; private Lazy _tagService; private Lazy _contentService; private Lazy _userService; @@ -52,6 +54,7 @@ namespace Umbraco.Core.Services /// /// /// + /// public ServiceContext( IContentService contentService, IMediaService mediaService, @@ -69,7 +72,7 @@ namespace Umbraco.Core.Services ISectionService sectionService, IApplicationTreeService treeService, ITagService tagService, - INotificationService notificationService) + INotificationService notificationService, ILoggingService loggingService) { _tagService = new Lazy(() => tagService); _contentService = new Lazy(() => contentService); @@ -88,7 +91,7 @@ namespace Umbraco.Core.Services _memberService = new Lazy(() => memberService); _userService = new Lazy(() => userService); _notificationService = new Lazy(() => notificationService); - + _loggingService = new Lazy(() => loggingService); } /// @@ -174,6 +177,10 @@ namespace Umbraco.Core.Services _tagService = new Lazy(() => new TagService(provider, repositoryFactory.Value)); if (_memberGroupService == null) _memberGroupService = new Lazy(() => new MemberGroupService(provider, repositoryFactory.Value)); + + + if (_loggingService== null) + _loggingService = new Lazy(() => new LoggingService()); } @@ -328,6 +335,13 @@ namespace Umbraco.Core.Services { get { return _memberGroupService.Value; } } - + + /// + /// Gets the LoggingService + /// + public ILoggingService LoggingService + { + get { return _loggingService.Value; } + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 5d72a83243..089969ba3f 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -1,4 +1,4 @@ - + Debug @@ -106,7 +106,7 @@ True ..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll - + False @@ -315,6 +315,8 @@ + + diff --git a/src/Umbraco.Tests/MockTests.cs b/src/Umbraco.Tests/MockTests.cs index f8810fe67f..5e895ae9d1 100644 --- a/src/Umbraco.Tests/MockTests.cs +++ b/src/Umbraco.Tests/MockTests.cs @@ -5,6 +5,7 @@ using System.Text; using System.Web; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.UnitOfWork; using Umbraco.Core.Services; @@ -56,7 +57,7 @@ namespace Umbraco.Tests new Mock().Object, new Mock().Object, new Mock().Object, - new Mock().Object); + new Mock().Object, new Mock().Object); Assert.Pass(); } @@ -101,7 +102,7 @@ namespace Umbraco.Tests new Mock().Object, new Mock().Object, new Mock().Object, - new Mock().Object), + new Mock().Object, new Mock().Object), CacheHelper.CreateDisabledCacheHelper()); Assert.Pass(); From 79990b6a6ccbee0bdcb3cac63635d994b6990e92 Mon Sep 17 00:00:00 2001 From: Anthony Dang Date: Fri, 21 Nov 2014 12:38:27 +0000 Subject: [PATCH 2/3] Cleaned up interface as per Shannons comments https://github.com/umbraco/Umbraco-CMS/pull/559/files#r20683448 --- src/Umbraco.Core/Services/ILoggingService.cs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/Umbraco.Core/Services/ILoggingService.cs b/src/Umbraco.Core/Services/ILoggingService.cs index 1094428c5e..6348e2495c 100644 --- a/src/Umbraco.Core/Services/ILoggingService.cs +++ b/src/Umbraco.Core/Services/ILoggingService.cs @@ -7,34 +7,17 @@ namespace Umbraco.Core.Services /// public interface ILoggingService { - void Error(string message, Exception exception); void Error(Type callingType, string message, Exception exception); void Warn(Type callingType, string message, params Func[] formatItems); - void Warn(Type callingType, string message, bool showHttpTrace, params Func[] formatItems); + void WarnWithException(Type callingType, string message, Exception e, params Func[] formatItems); - void WarnWithException(Type callingType, string message, bool showHttpTrace, Exception e, params Func[] formatItems); - - void Warn(string message, params Func[] formatItems); - void Warn(string message, bool showHttpTrace, params Func[] formatItems); - void WarnWithException(string message, Exception e, params Func[] formatItems); - void WarnWithException(string message, bool showHttpTrace, Exception e, params Func[] formatItems); - - void Info(Func generateMessage); void Info(Type callingType, Func generateMessage); void Info(Type type, string generateMessageFormat, params Func[] formatItems); - void Info(string generateMessageFormat, params Func[] formatItems); - - void Debug(Func generateMessage); - void Debug(Type callingType, Func generateMessage); void Debug(Type type, string generateMessageFormat, params Func[] formatItems); - - void Debug(string generateMessageFormat, params Func[] formatItems); - - void Debug(string generateMessageFormat, bool showHttpTrace, params Func[] formatItems); } } \ No newline at end of file From e03988dd813027215b9971b421443dbdfa22b4a4 Mon Sep 17 00:00:00 2001 From: Anthony Dang Date: Fri, 21 Nov 2014 12:38:56 +0000 Subject: [PATCH 3/3] Removed regions from LoggingService to expose code. --- src/Umbraco.Core/Services/LoggingService.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Core/Services/LoggingService.cs b/src/Umbraco.Core/Services/LoggingService.cs index 7c6bbc8958..43cd5b0cba 100644 --- a/src/Umbraco.Core/Services/LoggingService.cs +++ b/src/Umbraco.Core/Services/LoggingService.cs @@ -43,7 +43,7 @@ namespace Umbraco.Core.Services return "[Thread " + Thread.CurrentThread.ManagedThreadId + "] " + generateMessageFormat; } - #region Error + /// /// Adds an error log /// @@ -62,9 +62,7 @@ namespace Umbraco.Core.Services logger.Error(PrefixThreadId(message), exception); } - #endregion - #region Warn public void Warn(Type callingType, string message, params Func[] formatItems) { @@ -139,9 +137,9 @@ namespace Umbraco.Core.Services WarnWithException(typeof(T), message, showHttpTrace, e, formatItems); } - #endregion + + - #region Info /// /// Traces a message, only generating the message if tracing is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled. /// @@ -190,9 +188,10 @@ namespace Umbraco.Core.Services { Info(typeof(T), generateMessageFormat, formatItems); } - #endregion + + + - #region Debug /// /// Debugs a message, only generating the message if tracing is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled. /// @@ -261,7 +260,5 @@ namespace Umbraco.Core.Services Debug(typeof(T), generateMessageFormat, formatItems); } - #endregion - } }