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 "";
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;}