diff --git a/config templates/config/umbracoSettings.config b/config templates/config/umbracoSettings.config index a64f3c6b50..61409e1a08 100644 --- a/config templates/config/umbracoSettings.config +++ b/config templates/config/umbracoSettings.config @@ -113,6 +113,9 @@ + + + diff --git a/umbraco/businesslogic/Interfaces/ILog.cs b/umbraco/businesslogic/Interfaces/ILog.cs new file mode 100644 index 0000000000..fdb042f017 --- /dev/null +++ b/umbraco/businesslogic/Interfaces/ILog.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using umbraco.DataLayer; + +namespace umbraco.BusinessLogic.Interfaces +{ + public interface ILog + { + void Add(LogTypes logType, User user, int nodeId, string comment); + void Add(Exception exception); + void CleanLogs(int maximumAgeOfLogsInMinutes); + List GetLogItems(LogTypes Type, DateTime SinceDate); + List GetLogItems(int NodeId); + List GetLogItems(User user, DateTime SinceDate); + List GetLogItems(User user, LogTypes Type, DateTime SinceDate); + List GetAuditLogReader(int NodeId); + } +} diff --git a/umbraco/businesslogic/Log.cs b/umbraco/businesslogic/Log.cs index 22e54de7fc..2225429a5b 100644 --- a/umbraco/businesslogic/Log.cs +++ b/umbraco/businesslogic/Log.cs @@ -4,15 +4,57 @@ using System.Diagnostics; using System.Threading; using umbraco.DataLayer; +using System.Collections.Generic; +using System.Reflection; +using umbraco.BusinessLogic.Utils; namespace umbraco.BusinessLogic { - /// - /// Summary description for Log. - /// - public class Log - { - #region Statics + /// + /// Summary description for Log. + /// + public class Log + { + #region Statics + private Interfaces.ILog m_externalLogger = null; + private bool m_externalLoggerInitiated = false; + + internal Interfaces.ILog ExternalLogger + { + get + { + if (!m_externalLoggerInitiated) + { + m_externalLoggerInitiated = true; + if (!String.IsNullOrEmpty(UmbracoSettings.ExternalLoggerAssembly) + && !String.IsNullOrEmpty(UmbracoSettings.ExternalLoggerType)) + { + try + { + string assemblyPath = IO.IOHelper.MapPath(UmbracoSettings.ExternalLoggerAssembly); + m_externalLogger = Assembly.LoadFrom(assemblyPath).CreateInstance(UmbracoSettings.ExternalLoggerType) as Interfaces.ILog; + } + catch (Exception ee) + { + Log.AddLocally(LogTypes.Error, User.GetUser(0), -1, + "Error loading external logger: " + ee.ToString()); + } + } + } + + return m_externalLogger; + } + } + + + #region Singleton + + public static Log Instance + { + get { return Singleton.Instance; } + } + + #endregion private static ISqlHelper SqlHelper { @@ -26,25 +68,82 @@ namespace umbraco.BusinessLogic /// The user adding the item. /// The affected node id. /// Comment. - public static void Add(LogTypes type, User user, int nodeId, string comment) - { - if(!UmbracoSettings.EnableLogging) return; + public static void Add(LogTypes type, User user, int nodeId, string comment) + { + if (Instance.ExternalLogger != null) + { + Instance.ExternalLogger.Add(type, user, nodeId, comment); - if (UmbracoSettings.DisabledLogTypes != null && - UmbracoSettings.DisabledLogTypes.SelectSingleNode(String.Format("//logTypeAlias [. = '{0}']", type.ToString().ToLower())) == null) { - - if (comment.Length > 3999) - comment = comment.Substring(0, 3955) + "..."; - - if (UmbracoSettings.EnableAsyncLogging) { - ThreadPool.QueueUserWorkItem( - delegate { AddSynced(type, user == null ? 0 : user.Id, nodeId, comment); }); - return; + // Audit trail too? + if (!UmbracoSettings.ExternalLoggerLogAuditTrail && type.GetType().GetField(type.ToString()).GetCustomAttributes(typeof(AuditTrailLogItem), true) != null) + { + AddLocally(type, user, nodeId, comment); } - - AddSynced(type, user == null ? 0 : user.Id, nodeId, comment); } - } + else + { + if (!UmbracoSettings.EnableLogging) return; + + if (UmbracoSettings.DisabledLogTypes != null && + UmbracoSettings.DisabledLogTypes.SelectSingleNode(String.Format("//logTypeAlias [. = '{0}']", type.ToString().ToLower())) == null) + { + + if (comment.Length > 3999) + comment = comment.Substring(0, 3955) + "..."; + + if (UmbracoSettings.EnableAsyncLogging) + { + ThreadPool.QueueUserWorkItem( + delegate { AddSynced(type, user == null ? 0 : user.Id, nodeId, comment); }); + return; + } + + AddSynced(type, user == null ? 0 : user.Id, nodeId, comment); + } + } + } + + public void AddException(Exception ee) + { + if (ExternalLogger != null) + { + ExternalLogger.Add(ee); + } + else + { + Exception ex2 = ee; + string error = String.Empty; + string errorMessage = string.Empty; + while (ex2 != null) + { + error += ex2.ToString(); + ex2 = ex2.InnerException; + } + Add(LogTypes.Error, -1, error); + } + } + + /// + /// Adds the specified log item to the Umbraco log no matter if an external logger has been defined. + /// + /// The log type. + /// The user adding the item. + /// The affected node id. + /// Comment. + public static void AddLocally(LogTypes type, User user, int nodeId, string comment) + { + if (comment.Length > 3999) + comment = comment.Substring(0, 3955) + "..."; + + if (UmbracoSettings.EnableAsyncLogging) + { + ThreadPool.QueueUserWorkItem( + delegate { AddSynced(type, user == null ? 0 : user.Id, nodeId, comment); }); + return; + } + + AddSynced(type, user == null ? 0 : user.Id, nodeId, comment); + } /// /// Adds the specified log item to the log without any user information attached. @@ -52,10 +151,10 @@ namespace umbraco.BusinessLogic /// The log type. /// The affected node id. /// Comment. - public static void Add(LogTypes type, int nodeId, string comment) - { - Add(type, null, nodeId, comment); - } + public static void Add(LogTypes type, int nodeId, string comment) + { + Add(type, null, nodeId, comment); + } /// /// Adds a log item to the log immidiately instead of Queuing it as a work item. @@ -64,23 +163,99 @@ namespace umbraco.BusinessLogic /// The user id. /// The node id. /// The comment. - public static void AddSynced(LogTypes type, int userId, int nodeId, string comment) - { - try - { - SqlHelper.ExecuteNonQuery( - "insert into umbracoLog (userId, nodeId, logHeader, logComment) values (@userId, @nodeId, @logHeader, @comment)", - SqlHelper.CreateParameter("@userId", userId), - SqlHelper.CreateParameter("@nodeId", nodeId), - SqlHelper.CreateParameter("@logHeader", type.ToString()), - SqlHelper.CreateParameter("@comment", comment)); - } - catch(Exception e) - { - Debug.WriteLine(e.ToString(), "Error"); - Trace.WriteLine(e.ToString()); - } - } + public static void AddSynced(LogTypes type, int userId, int nodeId, string comment) + { + try + { + SqlHelper.ExecuteNonQuery( + "insert into umbracoLog (userId, nodeId, logHeader, logComment) values (@userId, @nodeId, @logHeader, @comment)", + SqlHelper.CreateParameter("@userId", userId), + SqlHelper.CreateParameter("@nodeId", nodeId), + SqlHelper.CreateParameter("@logHeader", type.ToString()), + SqlHelper.CreateParameter("@comment", comment)); + } + catch (Exception e) + { + Debug.WriteLine(e.ToString(), "Error"); + Trace.WriteLine(e.ToString()); + } + } + + public List GetAuditLogItems(int NodeId) + { + if (UmbracoSettings.ExternalLoggerLogAuditTrail && ExternalLogger != null) + return ExternalLogger.GetAuditLogReader(NodeId); + else + return LogItem.ConvertIRecordsReader(SqlHelper.ExecuteReader( + "select userId, nodeId, logHeader, DateStamp, logComment from umbracoLog where nodeId = @id and logHeader not in ('open','system') order by DateStamp desc", + SqlHelper.CreateParameter("@id", NodeId))); + } + + public List GetLogItems(LogTypes type, DateTime sinceDate) + { + if (ExternalLogger != null) + return ExternalLogger.GetLogItems(type, sinceDate); + else + return LogItem.ConvertIRecordsReader(SqlHelper.ExecuteReader( + "select userId, NodeId, DateStamp, logHeader, logComment from umbracoLog where logHeader = @logHeader and DateStamp >= @dateStamp order by dateStamp desc", + SqlHelper.CreateParameter("@logHeader", type), + SqlHelper.CreateParameter("@dateStamp", sinceDate))); + } + + public List GetLogItems(int nodeId) + { + if (ExternalLogger != null) + return ExternalLogger.GetLogItems(nodeId); + else + return LogItem.ConvertIRecordsReader(SqlHelper.ExecuteReader( + "select userId, NodeId, DateStamp, logHeader, logComment from umbracoLog where id = @id order by dateStamp desc", + SqlHelper.CreateParameter("@id", nodeId))); + } + + public List GetLogItems(User user, DateTime sinceDate) + { + if (ExternalLogger != null) + return ExternalLogger.GetLogItems(user, sinceDate); + else + return LogItem.ConvertIRecordsReader(SqlHelper.ExecuteReader( + "select userId, NodeId, DateStamp, logHeader, logComment from umbracoLog where UserId = @user and DateStamp >= @dateStamp order by dateStamp desc", + SqlHelper.CreateParameter("@user", user.Id), + SqlHelper.CreateParameter("@dateStamp", sinceDate))); + } + + public List GetLogItems(User user, LogTypes type, DateTime sinceDate) + { + if (ExternalLogger != null) + return ExternalLogger.GetLogItems(user, type, sinceDate); + else + return LogItem.ConvertIRecordsReader(SqlHelper.ExecuteReader( + "select userId, NodeId, DateStamp, logHeader, logComment from umbracoLog where UserId = @user and logHeader = @logHeader and DateStamp >= @dateStamp order by dateStamp desc", + SqlHelper.CreateParameter("@logHeader", type), + SqlHelper.CreateParameter("@user", user.Id), + SqlHelper.CreateParameter("@dateStamp", sinceDate))); + } + + public static void CleanLogs(int maximumAgeOfLogsInMinutes) + { + if (Instance.ExternalLogger != null) + Instance.ExternalLogger.CleanLogs(maximumAgeOfLogsInMinutes); + else + { + try + { + DateTime oldestPermittedLogEntry = DateTime.Now.Subtract(new TimeSpan(0, maximumAgeOfLogsInMinutes, 0)); + SqlHelper.ExecuteNonQuery("delete from umbracoLog where datestamp < @oldestPermittedLogEntry and logHeader in ('open','system')", + SqlHelper.CreateParameter("@oldestPermittedLogEntry", oldestPermittedLogEntry)); + Add(LogTypes.System, -1, "Log scrubbed. Removed all items older than " + oldestPermittedLogEntry); + } + catch (Exception e) + { + Debug.WriteLine(e.ToString(), "Error"); + Trace.WriteLine(e.ToString()); + } + } + } + #region New GetLog methods - DataLayer layer compatible /// @@ -88,6 +263,7 @@ namespace umbraco.BusinessLogic /// /// The node id. /// A reader for the audit log. + [Obsolete("Use the Instance.GetAuditLogItems method which return a list of LogItems instead")] public static IRecordsReader GetAuditLogReader(int NodeId) { return SqlHelper.ExecuteReader( @@ -101,6 +277,7 @@ namespace umbraco.BusinessLogic /// The type of log message. /// The start date. /// A reader for the log. + [Obsolete("Use the Instance.GetLogItems method which return a list of LogItems instead")] public static IRecordsReader GetLogReader(LogTypes Type, DateTime SinceDate) { return SqlHelper.ExecuteReader( @@ -114,6 +291,7 @@ namespace umbraco.BusinessLogic /// /// The node id. /// A reader for the log. + [Obsolete("Use the Instance.GetLogItems method which return a list of LogItems instead")] public static IRecordsReader GetLogReader(int NodeId) { return SqlHelper.ExecuteReader( @@ -127,6 +305,7 @@ namespace umbraco.BusinessLogic /// The user. /// The start date. /// A reader for the log. + [Obsolete("Use the Instance.GetLogItems method which return a list of LogItems instead")] public static IRecordsReader GetLogReader(User user, DateTime SinceDate) { return SqlHelper.ExecuteReader( @@ -142,6 +321,7 @@ namespace umbraco.BusinessLogic /// The type of log message. /// The since date. /// A reader for the log. + [Obsolete("Use the Instance.GetLogItems method which return a list of LogItems instead")] public static IRecordsReader GetLogReader(User user, LogTypes Type, DateTime SinceDate) { return SqlHelper.ExecuteReader( @@ -149,358 +329,205 @@ namespace umbraco.BusinessLogic SqlHelper.CreateParameter("@logHeader", Type.ToString()), SqlHelper.CreateParameter("@user", user.Id), SqlHelper.CreateParameter("@dateStamp", SinceDate)); - } + } #endregion - #region Old GetLog methods - DataLayer incompatible - #pragma warning disable 618 // ConvertToDataSet is obsolete - - /// - /// Gets the log. - /// - /// The type. - /// The start date. - /// The log. - /// Only guaranteed to work with SQL Server. Obsolete. - [Obsolete("Not compatible with the data layer. Use GetLogReader instead.", true)] - public static DataSet GetLog(LogTypes Type, DateTime SinceDate) - { - try - { - return ConvertToDataSet(GetLogReader(Type, SinceDate)); - } - catch (Exception) - { - throw new Exception("The GetLog method is not compatible with the data layer."); - } - } - - /// - /// Returns a dataset of Log items with a specific type since a specific date. - /// - /// The type. - /// The start date. - /// Maximum number of results. - /// The log. - /// Only guaranteed to work with SQL Server. Obsolete. - [Obsolete("Not compatible with the data layer. Use GetLogReader instead.", true)] - public static DataSet GetLog(LogTypes Type, DateTime SinceDate, int Limit) - { - try - { - return ConvertToDataSet(SqlHelper.ExecuteReader( - "select top (" + Limit + - ") userId, NodeId, DateStamp, logHeader, logComment from umbracoLog where logHeader = @logHeader and DateStamp >= @dateStamp order by dateStamp desc", - SqlHelper.CreateParameter("@logHeader", Type.ToString()), - SqlHelper.CreateParameter("@dateStamp", SinceDate))); - } - catch (Exception) - { - throw new Exception("The GetLog method is not compatible with the data layer."); - } - } - - /// - /// Returns a dataset of Log items for a specific node - /// - /// The node id. - /// The log. - /// Only guaranteed to work with SQL Server. Obsolete. - [Obsolete("Not compatible with the data layer. Use GetLogReader instead.", true)] - public static DataSet GetLog(int NodeId) - { - try - { - return ConvertToDataSet(GetLogReader(NodeId)); - } - catch (Exception) - { - throw new Exception("The GetLog method is not compatible with the data layer."); - } - } - - /// - /// Returns a dataset of audit Log items for a specific node with more detailed user information - /// - /// The node id. - /// The log. - /// Only guaranteed to work with SQL Server. Obsolete. - [Obsolete("Not compatible with the data layer. Use GetAuditLogReader instead.", true)] - public static DataSet GetAuditLog(int NodeId) - { - try - { - return ConvertToDataSet(GetAuditLogReader(NodeId)); - } - catch (Exception) - { - throw new Exception("The GetAuditLog method is not compatible with the data layer."); - } - } - - /// - /// Returns a dataset of Log items for a specific user, since a specific date - /// - /// The user. - /// The start date. - /// The log. - /// Only guaranteed to work with SQL Server. Obsolete. - [Obsolete("Not compatible with the data layer. Use GetAuditLogReader instead.", true)] - public static DataSet GetLog(User u, DateTime SinceDate) - { - try - { - return ConvertToDataSet(GetLogReader(u, SinceDate)); - } - catch (Exception) - { - throw new Exception("The GetLog method is not compatible with the data layer."); - } - } - - /// - /// Returns a dataset of Log items for a specific user of a specific type, since a specific date - /// - /// The user. - /// The type. - /// The start date. - /// The log. - /// Only guaranteed to work with SQL Server. Obsolete. - [Obsolete("Not compatible with the data layer. Use GetLogReader instead.", true)] - public static DataSet GetLog(User u, LogTypes Type, DateTime SinceDate) - { - try - { - return ConvertToDataSet(GetLogReader(u, Type, SinceDate)); - } - catch (Exception) - { - throw new Exception("The GetLog method is not compatible with the data layer."); - } - } - - /// - /// Returns a dataset of Log items for a specific user of a specific type, since a specific date - /// - /// The user. - /// The type. - /// The since date. - /// The limit. - /// The log. - /// Only guaranteed to work with SQL Server. Obsolete. - [Obsolete("Not compatible with the data layer. Use GetLogReader instead.", true)] - public static DataSet GetLog(User u, LogTypes Type, DateTime SinceDate, int Limit) - { - try - { - return ConvertToDataSet(SqlHelper.ExecuteReader( - "select top (" + Limit + - ") userId, NodeId, DateStamp, logHeader, logComment from umbracoLog where UserId = @user and logHeader = @logHeader and DateStamp >= @dateStamp order by dateStamp desc", - SqlHelper.CreateParameter("@logHeader", Type.ToString()), - SqlHelper.CreateParameter("@user", u.Id), - SqlHelper.CreateParameter("@dateStamp", SinceDate))); - } - catch (Exception) - { - throw new Exception("The GetLog method is not compatible with the data layer."); - } - } - - /// - /// Converts a records reader to a data set. - /// - /// The records reader. - /// The data set - /// Only works with DataLayer.SqlHelpers.SqlServer.SqlServerDataReader. - /// When not an DataLayer.SqlHelpers.SqlServer.SqlServerDataReader. - [Obsolete("Temporary workaround for old GetLog methods.", false)] - private static DataSet ConvertToDataSet(IRecordsReader recordsReader) - { - // Get the internal RawDataReader (obsolete) - System.Data.SqlClient.SqlDataReader reader - = ((DataLayer.SqlHelpers.SqlServer.SqlServerDataReader)recordsReader).RawDataReader; - DataSet dataSet = new DataSet(); - do - { - DataTable dataTable = new DataTable(); - DataTable schemaTable = reader.GetSchemaTable(); - - if (schemaTable != null) - { - // A query returning records was executed - foreach (DataRow dataRow in schemaTable.Rows) - { - // Create a column name that is unique in the data table - string columnName = (string)dataRow["ColumnName"]; - // Add the column definition to the data table - DataColumn column = new DataColumn(columnName, (Type)dataRow["DataType"]); - dataTable.Columns.Add(column); - } - - dataSet.Tables.Add(dataTable); - - // Fill the data table we just created - while (reader.Read()) - { - DataRow dataRow = dataTable.NewRow(); - for (int i = 0; i < reader.FieldCount; i++) - dataRow[i] = reader.GetValue(i); - dataTable.Rows.Add(dataRow); - } - } - else - { - // No records were returned, return number of rows affected - dataTable.Columns.Add(new DataColumn("RowsAffected")); - dataSet.Tables.Add(dataTable); - DataRow rowsAffectedRow = dataTable.NewRow(); - rowsAffectedRow[0] = reader.RecordsAffected; - dataTable.Rows.Add(rowsAffectedRow); - } - } - // Go trough all result sets - while (reader.NextResult()); - - // Close the data reader so the underlying connection is closed - recordsReader.Close(); - - return dataSet; - } - #pragma warning restore 618 - - #endregion - - public static void CleanLogs(int maximumAgeOfLogsInMinutes) - { - try - { - DateTime oldestPermittedLogEntry = DateTime.Now.Subtract(new TimeSpan(0, maximumAgeOfLogsInMinutes, 0)); - SqlHelper.ExecuteNonQuery("delete from umbracoLog where datestamp < @oldestPermittedLogEntry and logHeader in ('open','system')", - SqlHelper.CreateParameter("@oldestPermittedLogEntry", oldestPermittedLogEntry)); - Add(LogTypes.System, -1, "Log scrubbed. Removed all items older than " + oldestPermittedLogEntry); - } - catch (Exception e) - { - Debug.WriteLine(e.ToString(), "Error"); - Trace.WriteLine(e.ToString()); - } - } - #endregion } /// /// The collection of available log types. /// - public enum LogTypes - { + public enum LogTypes + { /// /// Used when new nodes are added /// - New, + [AuditTrailLogItem] + New, /// /// Used when nodes are saved /// - Save, + [AuditTrailLogItem] + Save, /// /// Used when nodes are opened /// - Open, + [AuditTrailLogItem] + Open, /// /// Used when nodes are deleted /// - Delete, + [AuditTrailLogItem] + Delete, /// /// Used when nodes are published /// - Publish, + [AuditTrailLogItem] + Publish, /// /// Used when nodes are send to publishing /// - SendToPublish, + [AuditTrailLogItem] + SendToPublish, /// /// Used when nodes are unpublished /// - UnPublish, + [AuditTrailLogItem] + UnPublish, /// /// Used when nodes are moved /// - Move, + [AuditTrailLogItem] + Move, /// /// Used when nodes are copied /// - Copy, + [AuditTrailLogItem] + Copy, /// /// Used when nodes are assígned a domain /// - AssignDomain, + [AuditTrailLogItem] + AssignDomain, /// /// Used when public access are changed for a node /// - PublicAccess, + [AuditTrailLogItem] + PublicAccess, /// /// Used when nodes are sorted /// - Sort, + [AuditTrailLogItem] + Sort, /// /// Used when a notification are send to a user /// - Notify, + [AuditTrailLogItem] + Notify, /// /// Used when a user logs into the umbraco back-end /// - Login, + Login, /// /// Used when a user logs out of the umbraco back-end /// - Logout, + Logout, /// /// Used when a user login fails /// - LoginFailure, + LoginFailure, /// /// General system notification /// - System, + [AuditTrailLogItem] + System, /// /// System debugging notification /// - Debug, + Debug, /// /// System error notification /// - Error, + Error, /// /// Notfound error notification /// - NotFound, + NotFound, /// /// Used when a node's content is rolled back to a previous version /// - RollBack, + [AuditTrailLogItem] + RollBack, /// /// Used when a package is installed /// - PackagerInstall, + [AuditTrailLogItem] + PackagerInstall, /// /// Used when a package is uninstalled /// - PackagerUninstall, + [AuditTrailLogItem] + PackagerUninstall, /// /// Used when a ping is send to/from the system /// - Ping, + Ping, /// /// Used when a node is send to translation /// - SendToTranslate, + [AuditTrailLogItem] + SendToTranslate, /// /// Notification from a Scheduled task. /// - ScheduledTask, + ScheduledTask, /// /// Use this log action for custom log messages that should be shown in the audit trail /// + [AuditTrailLogItem] Custom - } + } + + public class LogItem + { + public int UserId { get; set; } + public int NodeId { get; set; } + public DateTime Timestamp { get; set; } + public LogTypes LogType { get; set; } + public string Comment { get; set; } + + public LogItem() + { + + } + + public LogItem(int userId, int nodeId, DateTime timestamp, LogTypes logType, string comment) + { + UserId = userId; + NodeId = nodeId; + Timestamp = timestamp; + LogType = logType; + Comment = comment; + } + + public static List ConvertIRecordsReader(IRecordsReader reader) + { + List items = new List(); + while (reader.Read()) + { + items.Add(new LogItem( + reader.GetInt("userId"), + reader.GetInt("nodeId"), + reader.GetDateTime("DateStamp"), + convertLogHeader(reader.GetString("logHeader")), + reader.GetString("logComment"))); + } + + return items; + + } + + private static LogTypes convertLogHeader(string logHeader) + { + try + { + return (LogTypes)Enum.Parse(typeof(LogTypes), logHeader, true); + } + catch + { + return LogTypes.Custom; + } + } + } + + public class AuditTrailLogItem : Attribute + { + public AuditTrailLogItem() + { + + } + } + + } \ No newline at end of file diff --git a/umbraco/businesslogic/UmbracoSettings.cs b/umbraco/businesslogic/UmbracoSettings.cs index 6f5d1f0688..ca66c7f588 100644 --- a/umbraco/businesslogic/UmbracoSettings.cs +++ b/umbraco/businesslogic/UmbracoSettings.cs @@ -146,6 +146,56 @@ namespace umbraco } } + /// + /// Gets the assembly of an external logger that can be used to store log items in 3rd party systems + /// + public static string ExternalLoggerAssembly + { + get + { + XmlNode value = GetKeyAsNode("/settings/logging/externalLogger"); + if (value != null) + { + return value.Attributes["assembly"].Value; + } + return ""; + } + } + /// + /// Gets the type of an external logger that can be used to store log items in 3rd party systems + /// + public static string ExternalLoggerType + { + get + { + XmlNode value = GetKeyAsNode("/settings/logging/externalLogger"); + if (value != null) + { + return value.Attributes["type"].Value; + } + return ""; + } + } + + /// + /// Long Audit Trail to external log too + /// + public static bool ExternalLoggerLogAuditTrail + { + get + { + XmlNode value = GetKeyAsNode("/settings/logging/externalLogger"); + if (value != null) + { + string logAuditTrail = value.Attributes["logAuditTrail"].Value; + bool result; + if (!string.IsNullOrEmpty(logAuditTrail) && bool.TryParse(logAuditTrail, out result)) + return result; + } + return false; + } + } + /// /// Gets a value indicating whether the logs will be auto cleaned /// diff --git a/umbraco/businesslogic/Utils/Singleton.cs b/umbraco/businesslogic/Utils/Singleton.cs new file mode 100644 index 0000000000..d509ba1bd5 --- /dev/null +++ b/umbraco/businesslogic/Utils/Singleton.cs @@ -0,0 +1,45 @@ +using System; + +namespace umbraco.BusinessLogic.Utils +{ + /// + /// + /// Threadsafe Singleton best practice design pattern template + /// + /// Sample: + /// + /// public class Demo + /// { + /// public static Form1 instance1 + /// { + /// get + /// { + /// return Singleton.Instance; + /// } + /// } + /// } + /// + /// Any class that implements default constructor + public sealed class Singleton where T : new() + { + private Singleton() + { + } + + public static T Instance + { + get { return Nested.instance; } + } + + private class Nested + { + // Explicit static constructor to tell C# compiler + // not to mark type as beforefieldinit + static Nested() + { + } + + internal static readonly T instance = new T(); + } + } +} diff --git a/umbraco/businesslogic/umbraco.businesslogic.csproj b/umbraco/businesslogic/umbraco.businesslogic.csproj index b038dd5ef5..1c600ce937 100644 --- a/umbraco/businesslogic/umbraco.businesslogic.csproj +++ b/umbraco/businesslogic/umbraco.businesslogic.csproj @@ -153,6 +153,7 @@ Code + @@ -181,6 +182,7 @@ + Code diff --git a/umbraco/presentation/content.cs b/umbraco/presentation/content.cs index b6dea99474..fe3e5c0be9 100644 --- a/umbraco/presentation/content.cs +++ b/umbraco/presentation/content.cs @@ -14,6 +14,7 @@ using umbraco.cms.businesslogic.cache; using umbraco.cms.businesslogic.web; using umbraco.DataLayer; using umbraco.IO; +using umbraco.BusinessLogic.Utils; namespace umbraco { diff --git a/umbraco/presentation/umbraco.presentation.csproj b/umbraco/presentation/umbraco.presentation.csproj index 782399d97b..0874714733 100644 --- a/umbraco/presentation/umbraco.presentation.csproj +++ b/umbraco/presentation/umbraco.presentation.csproj @@ -374,7 +374,6 @@ Code - Code diff --git a/umbraco/presentation/umbraco/dialogs/viewAuditTrail.aspx b/umbraco/presentation/umbraco/dialogs/viewAuditTrail.aspx index 9fa0b0989c..4a51de9800 100644 --- a/umbraco/presentation/umbraco/dialogs/viewAuditTrail.aspx +++ b/umbraco/presentation/umbraco/dialogs/viewAuditTrail.aspx @@ -15,17 +15,18 @@ +
- <%=umbraco.ui.Text("action")%> + <%=umbraco.ui.Text("action")%>   - <%# FormatAction(DataBinder.Eval(Container.DataItem, "Action", "{0}")) %> + <%# FormatAction(DataBinder.Eval(Container.DataItem, "LogType", "{0}")) %> @@ -35,7 +36,7 @@ - <%# DataBinder.Eval(Container.DataItem, "User", "{0}") %> + <%# umbraco.BusinessLogic.User.GetUser(int.Parse(DataBinder.Eval(Container.DataItem, "UserId", "{0}"))).Name%> @@ -45,7 +46,7 @@ - <%# DataBinder.Eval(Container.DataItem, "Date", "{0:D} {0:T}") %> + <%# DataBinder.Eval(Container.DataItem, "Timestamp", "{0:D} {0:T}") %> @@ -60,6 +61,7 @@ +
diff --git a/umbraco/presentation/umbraco/dialogs/viewAuditTrail.aspx.cs b/umbraco/presentation/umbraco/dialogs/viewAuditTrail.aspx.cs index 2d1428331b..57a3cf3378 100644 --- a/umbraco/presentation/umbraco/dialogs/viewAuditTrail.aspx.cs +++ b/umbraco/presentation/umbraco/dialogs/viewAuditTrail.aspx.cs @@ -21,7 +21,7 @@ namespace umbraco.presentation.umbraco.dialogs { // Put user code to initialize the page here //nodeName.Text = new cms.businesslogic.CMSNode(int.Parse(helper.Request("nodeID"))).Text; - auditLog.DataSource = BusinessLogic.Log.GetAuditLogReader(int.Parse(helper.Request("nodeID"))); + auditLog.DataSource = BusinessLogic.Log.Instance.GetAuditLogItems(int.Parse(UmbracoContext.Current.Request["nodeID"])); auditLog.DataBind(); auditLog.BorderWidth = 0; auditLog.BorderStyle = BorderStyle.None; @@ -37,9 +37,9 @@ namespace umbraco.presentation.umbraco.dialogs { if (string.Compare(a.Alias, action, true) == 0) { if(a.Icon.StartsWith(".")) - return "
"; + return "
" + ui.Text(action) + "
"; else - return "\"""; + return "\"" " + ui.Text(action); } } return action; diff --git a/umbraco/presentation/umbraco/dialogs/viewAuditTrail.aspx.designer.cs b/umbraco/presentation/umbraco/dialogs/viewAuditTrail.aspx.designer.cs index cbe834113a..00483889d1 100644 --- a/umbraco/presentation/umbraco/dialogs/viewAuditTrail.aspx.designer.cs +++ b/umbraco/presentation/umbraco/dialogs/viewAuditTrail.aspx.designer.cs @@ -1,10 +1,9 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.3082 // // Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. +// the code is regenerated. // //------------------------------------------------------------------------------ diff --git a/umbraco/presentation/umbraco_client/ui/default.css b/umbraco/presentation/umbraco_client/ui/default.css index 907874348b..f8b7ee5d10 100644 --- a/umbraco/presentation/umbraco_client/ui/default.css +++ b/umbraco/presentation/umbraco_client/ui/default.css @@ -530,7 +530,10 @@ guiEditor { padding-left:25px; } - +#auditTrailList span +{ + margin-left: 22px; +} .umbNitroList{} .umbNitroList input{float: left; display: block;}