Adding Windows Event Log Logging To Existing SSIS Packages via C#
While working with some SSIS logging, it occured to me that there's really no good way to globally apply the same logging to all packages on your server. For our production SSIS server, it would make sense to log all OnError events to the Application Event log. Then, whatever event log monitoring app you use can notify you of the package error (with details!). Thus, this app was born - an app to remove pre-existing LogProviders and add in the intended LogProvider and options.
This is really just an example of the implementation that worked for my purposes - I'm sure some of you would prefer to log elsewhere. This should be enough to get you going. Please drop a line in the Comments if you post alternative approaches.
Usage
SSISForcedLogging.Console.exe "Z:\SSIS Packages" or SSISForcedLogging.Console.Exe "Z:\SSIS Packages\Package1.dtsx"
For the following code, be sure to add References to:
- Microsoft.SqlServer.ManagedDTS
- System.configuration
Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | using System; using System.Configuration; using Microsoft.SqlServer.Dts.Runtime; using System.Reflection; using System.Collections; using System.IO; using System.Collections.Generic; namespace SSISForcedLogging.Console { class ColumnFilter { public bool Computer; public bool DataBytes; public bool ExecutionID; public bool MessageText; public bool Operator; public bool SourceID; public bool SourceName; public DTSEventColumnFilter GetDTSEventColumnFilter() { DTSEventColumnFilter dtsEventColumnFilter = new DTSEventColumnFilter(); dtsEventColumnFilter.DataBytes = this.DataBytes; dtsEventColumnFilter.Computer = this.Computer; dtsEventColumnFilter.ExecutionID = this.ExecutionID; dtsEventColumnFilter.MessageText = this.MessageText; dtsEventColumnFilter.Operator = this.Operator; dtsEventColumnFilter.SourceID = this.SourceID; dtsEventColumnFilter.SourceName = this.SourceName; return dtsEventColumnFilter; } } class Program { static void Main(string[] args) { if (args.Length != 1) { System.Console.WriteLine( "\nPlease specify a package path or directory\n"); Environment.Exit(-1); } string arg = args[0]; List<string> packages = new List<string>(); if (File.Exists(arg)) packages.Add(arg); else if (Directory.Exists(arg)) packages = GetPackagesFromDirectory(arg); else { System.Console.WriteLine( "\nInvalid package path or directory specified\n"); Environment.Exit(-1); } foreach (string pkgPath in packages) { System.Console.WriteLine( string.Format("Updating: {0}", pkgPath)); Application dts = new Application(); Package pkg = dts.LoadPackage(pkgPath, null); RemoveOldLogsFromPackage(ref pkg); AddLogToPackage(ref pkg); System.Console.WriteLine( string.Format("Saving: {0}", pkgPath)); dts.SaveToXml(pkgPath, pkg, null); } } public static void AddLogToPackage(ref Package Pkg) { // Add new provider Pkg.LoggingMode = DTSLoggingMode.Enabled; LogProvider log = Pkg.LogProviders.Add( ConfigurationManager.AppSettings["logType"]); log.Name = ConfigurationManager.AppSettings["logName"]; log.Description = ConfigurationManager.AppSettings["logDesc"]; Pkg.LoggingOptions.SelectedLogProviders.Add(log); LoggingOptions logOptions = Pkg.LoggingOptions; logOptions.EventFilterKind = DTSEventFilterKind.Inclusion; string[] events = ConfigurationManager .AppSettings["eventsToLog"] .Split(','); logOptions.EventFilter = events; ArrayList columnList = new ArrayList(); columnList.AddRange( ConfigurationManager .AppSettings["columnsToLog"] .Split(',')); ColumnFilter eventColumnFilter = new ColumnFilter(); foreach (FieldInfo field in eventColumnFilter.GetType().GetFields()) if (columnList.Contains(field.Name)) field.SetValue(eventColumnFilter, true); logOptions.SetColumnFilter( "OnError", eventColumnFilter.GetDTSEventColumnFilter()); } public static void RemoveOldLogsFromPackage(ref Package Pkg) { // Remove existing log provider selections int count = Pkg.LoggingOptions.SelectedLogProviders.Count; for (int i = 0; i < count; i++) Pkg.LoggingOptions.SelectedLogProviders.Remove(i); // Remove existing log providers count = Pkg.LogProviders.Count; for (int i = 0; i < count; i++) Pkg.LogProviders.Remove(i); RemoveOldLogsFromExecutable(Pkg.Executables); } public static void RemoveOldLogsFromExecutable(Executables Execs) { // reflection ftw int count; foreach(Executable exec in Execs) { foreach (PropertyInfo prop in exec.GetType().GetProperties()) { switch(prop.Name) { case "LoggingMode": prop.SetValue( exec, DTSLoggingMode.UseParentSetting, null); break; case "LoggingOptions": LoggingOptions opts = prop.GetValue( exec, null) as LoggingOptions; count = opts.SelectedLogProviders.Count; for (int i = 0; i < count; i++) opts.SelectedLogProviders.Remove(i); break; case "Executables": Executables execs = prop.GetValue( exec, null) as Executables; RemoveOldLogsFromExecutable(execs); break; } } } } public static List<string> GetPackagesFromDirectory(string Path) { List<string> files = new List<string>(); foreach (string d in Directory.GetDirectories(Path)) foreach (string f in GetPackagesFromDirectory(d)) files.Add(f); foreach (string f in Directory.GetFiles(Path, "*.dtsx")) files.Add(f); return files; } } } |
App.config
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="logType" value="DTS.LogProviderEventLog.1"/> <add key="logName" value="Windows Event Log Logging Provider (Forced)"/> <add key="logDesc" value="Logs Event info to Windows Event Log (Forced)"/> <add key="eventsToLog" value="OnError"/> <add key="columnsToLog" value="Computer,Operator,SourceName,SourceID,ExecutionID,MessageText"/> </appSettings> </configuration>



