Redux: Using an SSIS package to monitor and archive the default trace file
I’ve recently been asked for details regarding the SSIS package I wrote to copy and archive the default trace file which is generated by SQL Server. The contents of the file can be quite useful for troubleshooting or diagnosis purposes.
I’ve updated the package to work with SQL Server 2008 R2 and SQL Server 2012.
The detection of a new trace file is implemented using a Script Task which watches the \Log folder for new files. When a new file is detected it copies the previous file to an archive location. The logic is embedded in Visual Basic.NET (not my personal choice although I was limited in SQL Server 2005 when I wrote the package).
The archive process renames the file with the date and time and then copies the file to a chosen location. I should point out that I use expressions on a few variables to alter outputs such as the filename i.e. date_time_filename.
I also noticed that the service needs appropriate permissions to both access the \LOG directory and also copy to the target directory, in my scenario, this was \\server\share. When I was testing, I launch SSDT (SQL Server Data Tools) using Administrator privileges for testing purposes as a quick workround to permission issues).
Here is the code for the Script Task (apologies for the word wrap, the Live Writer plug-in seems to do this to fit it on the page). I have commented out some of the writeline commands I was using to debug the package when it was initially developed.
Code Snippet
- 'Disclaimer:
- 'The sample scripts and SSIS package are not supported under any Microsoft standard support program or service.
- 'The sample scripts and SSIS package are provided AS IS without warranty of any kind.
- 'Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
- 'The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
- 'In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits,
- 'business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.
- Public Sub Main()
- Dim vars As Variables
- Dim strComputer As String
- Dim objWMIService As Object
- Dim colMonitoredEvents As Object
- Dim objEventObject As Object
- Dim strSourceDirectory As String
- Dim strServerName As String
- Dim strSourceErrorLogDirectory As String
- Dim strSourceErrorLogDirectoryWithQuotes As String
- Try
- ' Use the SSIS variables in this code for the WMI query
- strServerName = Dts.Variables("v_ServerName").Value
- strSourceErrorLogDirectory = Dts.Variables("v_DT_SourceLogDirectory").Value
- Console.WriteLine("Servername: " + strServerName)
- Console.WriteLine("Monitoring \Log Directory: " + strSourceErrorLogDirectory)
- ' Replace \ with \\\\ which is needed for the WMI query
- strSourceErrorLogDirectory = Replace(strSourceErrorLogDirectory, "\", "\\\\")
- strSourceErrorLogDirectoryWithQuotes = Chr(34) & strSourceErrorLogDirectory & Chr(34)
- 'MsgBox("Server Name: " + strServerName)
- ' Connect to the WMI source
- objWMIService = GetObject("winmgmts:\\" & strServerName & "\root\cimv2")
- ' Monitor the error log folder for instances of ERRORLOG.1 as this is the file we want to archive
- ' The directory name is parameterised and populated from the SSIS variable
- ' Monitor the directory for new default trace files
- colMonitoredEvents = objWMIService.ExecNotificationQuery _
- ("SELECT * FROM __InstanceCreationEvent WITHIN 10 WHERE " _
- & "Targetinstance ISA 'CIM_DirectoryContainsFile' and " _
- & "TargetInstance.GroupComponent= " _
- & "'Win32_Directory.Name=" & strSourceErrorLogDirectoryWithQuotes & "'")
- objEventObject = colMonitoredEvents.NextEvent()
- 'MsgBox("A new file was just created: " + objEventObject.TargetInstance.PartComponent)
- Dim strReturned, strFilePath As String
- strReturned = objEventObject.TargetInstance.PartComponent
- strFilePath = Split(strReturned, "CIM_DataFile.Name=")(1)
- strFilePath = Replace(strFilePath, """", "")
- strFilePath = Replace(strFilePath, "\\", "\")
- 'MsgBox("Sliced file: " + strFilePath)
- ' strFilePath is C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\LOG\log_nnn.trc
- ' Array element (6) is log_nnn.trc, this assumes the above directory structure
- Dim strFilename As String
- 'strFilename = Split(strFilePath, "\")(6)
- 'MsgBox("Split: " + strFilename)
- strFilename = System.IO.Path.GetFileName(strFilePath)
- 'MsgBox("IO.Path: " + strFilename)
- ' If filename like log_ then enter this code path
- ' The default trace filename is always log_ so we can rely on this for filename matching
- If strFilename Like "log_*.trc" Then
- Console.WriteLine("A new default trace file was just created in \LOG called " + strFilename)
- Trace.WriteLine("A new default trace file was just created in \LOG called " + strFilename)
- ' Archive the previous default trace file
- 'MsgBox("Default Trace found, now process the file")
- Dim arrContainer As Array
- Dim intTraceFileNumber As Integer
- Dim strArchiveFileName As String
- arrContainer = Split(strFilename, "_")
- 'Console.WriteLine(arrContainer(0).ToString)
- 'Console.WriteLine(arrContainer(1).ToString)
- ' Split 1111.trc so we only store 1111 to convert to int
- arrContainer = Split(arrContainer(1), ".")
- ' This is the active default trace file number
- 'Console.WriteLine(arrContainer(0).ToString)
- ' Convert the active trace file number to int and decrease by 1
- intTraceFileNumber = CInt(arrContainer(0)) - 1
- ' Convert back to string and create the default trace file name
- strArchiveFileName = "log_" + CStr(intTraceFileNumber) + ".trc"
- 'Console.WriteLine("Archiving: " + strArchiveFileName + " to " + Dts.Variables("v_DT_DestinationDefaultTraceDirectory").Value)
- 'MsgBox(strArchiveFileName)
- 'Write the filename to the SSIS variable
- Dts.Variables("v_DT_ActiveFileName").Value = strArchiveFileName
- Console.WriteLine("Archiving: " + strArchiveFileName + " to " + Dts.Variables("v_DT_DestinationDefaultTraceDirectory").Value)
- MsgBox("Output to SSIS Variable: " + Dts.Variables("v_DT_ActiveFileName").Value + " strFilename: " + strArchiveFileName)
- ' Indicate success to move on to the next step
- Dts.TaskResult = ScriptResults.Success
- End If
- ' Error handling
- Catch ex As Exception
- Console.WriteLine(System.DateTime.Now.ToString + " - SSIS Script Task Error: " + ex.Message.ToString)
- Dts.TaskResult = ScriptResults.Failure
- End Try
- End Sub
I hope you find this useful.
I will try and attach the SSIS package to this post later.
Comments
- Anonymous
July 07, 2012
Thanks for this it will be very helpful. I don't see any need to apologize for it being in VB .NET. - Anonymous
July 22, 2012
Thanks for the usefull contribution having the package would would be great