I created a custom appender for CSV output. Note: i had to recompile log4net to make the RollFile method virtual. Hope this helps.
Scott
private static DevicePointValueCsvAppender CreateCsvAppender(string modbusMasterName, IEnumerable<DevicePointValue> values) { var appender = new DevicePointValueCsvAppender { MaxFileSize = ConfigurationManager.AppSettings[MaxFileSizeName].IfNotNull(max => OptionConverter.ToFileSize(max, DefaultMaxFileSize), DefaultMaxFileSize), MaxSizeRollBackups = ConfigurationManager.AppSettings[MaxSizeRollBackupsName].IfNotNull(max => Int32.Parse(max), DefaultMaxSizeRollBackups), Layout = new PatternLayout { ConversionPattern = PatternLayout.DefaultConversionPattern }, File = String.Format(CultureInfo.InvariantCulture, FileNameFormat, modbusMasterName), RollingStyle = RollingFileAppender.RollingMode.Composite, PreserveLogFileNameExtension = true, StaticLogFileName = false, AppendToFile = false };
appender.ActivateOptions();
return appender; }
private class DevicePointValueCsvAppender : RollingFileAppender { private bool _newFile = true;
/// <summary> /// Represents the configuration in the current log file target. /// </summary> public IEnumerable<DevicePointValue> CurrentConfiguration { get; set; }
public void WriteHeaderRow() { Debug.Assert(CurrentConfiguration != null, "Property CurrentConfiguration cannot be null.");
if (!CurrentConfiguration.Any()) return;
string titleRow = new string[] { "Timestamp".DoubleQuote() } .Concat(CurrentConfiguration.Select(dpv => GetEscapedCsvTitle(dpv.DevicePoint).DoubleQuote())) .Join(",");
DoAppend(CreateLoggingEvent(titleRow)); _newFile = false; }
public void WriteValuesRow(IEnumerable<DevicePointValue> values) { if (values == null) throw new ArgumentNullException("values");
if (!values.Any()) return;
if (_newFile || !ConfigurationsAreEqual(CurrentConfiguration, values)) { CurrentConfiguration = values;
if (!_newFile) RollOverSize();
_newFile = false; WriteHeaderRow(); }
string valueRow = new string[] { TimeZone.CurrentTimeZone.ToLocalTime(values.First().Timestamp).ToString().DoubleQuote() } .Concat(values.Select(dpv => dpv.Value.ToString().DoubleQuote())) .Join(",");
DoAppend(CreateLoggingEvent(valueRow)); } /// <summary> /// Escape any double quotes and include the unique device point info. /// </summary> internal static string GetEscapedCsvTitle(DevicePoint devicePoint) { return String.Format(CultureInfo.InvariantCulture, "{0} - ({1}:{2})", devicePoint.Name.IfNotNull(name => name.Replace("\"", "\"\"")), devicePoint.Address, devicePoint.ModbusDataType); }
/// <summary> /// NOTE: had to recompile log4net to make this method virtual. /// </summary> protected override void RollFile(string fromFile, string toFile) { base.RollFile(fromFile, toFile); _newFile = true; }
private static bool ConfigurationsAreEqual(IEnumerable<DevicePointValue> first, IEnumerable<DevicePointValue> second) { bool areEqual = true;
if (first.Count() != second.Count()) return false;
first.ForEach(second, (left, right) => { return areEqual = left.DevicePoint.Address == right.DevicePoint.Address && left.GetType() == right.GetType(); });
return areEqual; }
private static LoggingEvent CreateLoggingEvent(string message) { if (message == null) throw new ArgumentNullException("message");
var data = new LoggingEventData(); data.Level = Level.Info; data.Message = message;
return new LoggingEvent(data); } }
|