Ware House Solutions

  • Subscribe to our RSS feed.
  • Twitter
  • StumbleUpon
  • Reddit
  • Facebook
  • Digg

Wednesday, 28 March 2012

Easy Error Handling For Data Warehouse Sprocs

Posted on 15:09 by Unknown
Our Data Warehouse makes use of both SSIS packages and T-SQL Stored Procedures during the ETL phase. I use an audit schema borrowed from the excellent book SSIS Problem -Design-Solution to collect errors generated by SSIS. For T-SQL SP's I needed a simple way to collect errors which could be integrated into our DBA Monitoring Dashboard. This is what I did.

  1. Identified what data I wanted to capture.
  2. Built a table to store the errors
  3. Built a Stored Procedure to INSERT the errors
  4. Embedded the SP in the CATCH block of a TRY...CATCH in every Data Warehouse Procedure

What Error Data

Keep it simple, I thought. I needed to know what happended when. Who executed which procedure on what server. What was the error and where within the procedure did the error occur.

Most of that data can be collected using the built-in T-SQL ERROR_ system functions. This includes the error number, the line number on which the error occured, the severity, the state, which procedure caused the error and a full error message. The remaining details could be collected by accessing the system user, server name and setting a default on a created date time column.

The Table Design

I used the data types specified for the ERROR_ system functions on MSDN and created a surrogate primary key to ensure the table has a clustered index.

 CREATE TABLE [Metadata].[ErrorLog](  
[ErrorLogID] [int] IDENTITY(1,1) NOT NULL,
[SystemUser] [nvarchar](128) NOT NULL,
[CreatedDateTime] [datetime] NOT NULL,
[ServerName] [nvarchar](128) NOT NULL,
[ErrorNumber] [int] NOT NULL,
[ProcedureName] [nvarchar](128) NOT NULL,
[LineNumber] [int] NOT NULL,
[Severity] [int] NOT NULL,
[State] [int] NOT NULL,
[Message] [nvarchar](4000) NOT NULL,
CONSTRAINT [PK_ErrorLog] PRIMARY KEY CLUSTERED
(
[ErrorLogID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [Metadata].[ErrorLog] ADD DEFAULT (getdate()) FOR [CreatedDateTime]
GO

The Procedure Design

Again, keeping it as simple as possible and generic enough to be used across any solution was the main aim.
Most of the details will be passed through as parameters from the procedure which has encountered an error with the exception of Server Name and System User which I'll SET in this procedure.

The most interesting part of this procedure is the use of SERVERPROPERTY which can be configured to return a variety of useful information about the server environment. Be careful when using it to CONVERT it in order to assign it to a local variable as the returned data is in the form of a SQL_VARIANT. The rest of the procedure is pretty standard fare. A simple INSERT really.

 /*  
**********************************************************************************************************************************************************************************************************************
DW - InsertErrorLog
**********************************************************************************************************************************************************************************************************************
VERSION AUTHOR DATE COMMENTS
**********************************************************************************************************************************************************************************************************************
V1.0 GP 27/03/2012 Initial build of InsertErrorLog which is designed to take error details from inside a CATCH block and pass them to a central ErrorLog table
**********************************************************************************************************************************************************************************************************************
USAGE EXAMPLE
EXEC Common.InsertErrorLog 1234,'ProcedureName',1,17,1,'This is a test error message'
*/
CREATE PROCEDURE [Common].[InsertErrorLog]
(
@ErrorNumber INT,
@ProcedureName NVARCHAR(128),
@LineNumber INT,
@Severity INT,
@State INT,
@Message NVARCHAR(4000)
)
AS
SET NOCOUNT ON
DECLARE @SystemUser AS NVARCHAR(128)
DECLARE @ServerName AS NVARCHAR(128)
SET @SystemUser = SUSER_NAME()
SET @ServerName = CONVERT(SYSNAME, SERVERPROPERTY('SERVERNAME'))
-- POPULATE ERROR TABLE WITH SUBMITTED DATA
INSERT INTO DataWarehouse.Metadata.ErrorLog (SystemUser,ServerName,ErrorNumber,ProcedureName,LineNumber,Severity,State,Message)
VALUES (@SystemUser,@ServerName,@ErrorNumber,@ProcedureName,@LineNumber,@Severity,@State,@Message)
GO

An Example Procedure

Let's step through an example starting on line 22 where we enter the body of this stored procedure which is designed to TRUNCATE and repopulate a Time Dimension. On line 22 the BEGIN TRY is entered an all the subsequent code to line 54 is executed.

In the event of an error the CATCH block starting on line 56 is executed.

Within the CATCH block I assign the ERROR_ values to local variables on line 58-63.

On lines 64-65 I then EXECUTE the InsertErrorLog procedure with the local variables passed as a parameter. A row is then added to the table Metadata.ErrorLog

In my team we have a daily monitoring report which allows us to see problems in the overnight processing before and users report issues. This gives us a chance to get ahead of the problem by either fixing it or communicating with stakeholders. Before this was implemented we faced the spectacle of users periodically asking, "Is there a problem with the Data Warehouse.". Nowadays we can answer with certainty.

1:  USE [DataWarehouse]  
2: GO
3: /****** Object: StoredProcedure [DataMart].[LoadDIMTime] Script Date: 03/28/2012 22:56:55 ******/
4: SET ANSI_NULLS ON
5: GO
6: SET QUOTED_IDENTIFIER ON
7: GO
8: /*
9: ***************************************************************************************************************************************************************
10: DW - LoadDIMTime
11: ***************************************************************************************************************************************************************
12: VERSION AUTHOR DATE COMMENTS
13: ***************************************************************************************************************************************************************
14: V1.0 GP 10/01/2012 Initial build of DIMTime
15: V1.1 GP 27/03/2012 Added ErrorLog functionality in the CATCH block
16: ***************************************************************************************************************************************************************
17: USAGE EXAMPLE
18: EXEC DataMart.LoadDIMTime
19: */
20: ALTER PROCEDURE [DataMart].[LoadDIMTime]
21: AS
22: BEGIN TRY
23: -- START AFRESH WITH AN EMPTY TABLE
24: TRUNCATE TABLE DataWarehouse.DataMart.DIMTime
25: -- INSERT DIMENSION MEMBERS
26: INSERT INTO DataWarehouse.DataMart.DIMTime
27: ( Hour ,
28: Minute ,
29: Meridiem
30: )
31: SELECT Hour ,
32: Minute ,
33: Meridiem
34: FROM DataWarehouse.DataSource.vwTime
35: OPTION ( MAXRECURSION 0 )
36: -- ADD THE UNKNOWN MEMBER. SUSPEND THE IDENTITY DURING INSERT
37: IF NOT EXISTS ( SELECT TimeKey
38: FROM DataWarehouse.DataMart.DIMTime
39: WHERE TimeKey = -1 )
40: BEGIN
41: SET IDENTITY_INSERT DataWarehouse.DataMart.DIMTime ON
42: INSERT INTO DataWarehouse.DataMart.DIMTime
43: ( TimeKey ,
44: Hour ,
45: Minute ,
46: Meridiem
47: )
48: SELECT -1 AS TimeKey ,
49: 0 AS Hour ,
50: 0 AS Minute ,
51: 'UN' AS Meridiem
52: SET IDENTITY_INSERT DataWarehouse.DataMart.DIMTime OFF
53: END
54: END TRY
55: -- RETURN ERRORS WHEN ERRORS OCCUR
56: BEGIN CATCH
57: -- REPORT ERRORS
58: DECLARE @ErrorNumber INT = ERROR_NUMBER()
59: DECLARE @ErrorProcedure NVARCHAR(128) = ERROR_PROCEDURE()
60: DECLARE @ErrorLine INT = ERROR_LINE()
61: DECLARE @ErrorSeverity INT = ERROR_SEVERITY()
62: DECLARE @ErrorState INT = ERROR_STATE()
63: DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE()
64: EXEC Common.InsertErrorLog @ErrorNumber, @ErrorProcedure, @ErrorLine,
65: @ErrorSeverity, @ErrorState, @ErrorMessage
66: END CATCH
67: GO

Feel free to use the code and please email me any improvements you make.


Read More
Posted in Architecture, DBA, Error Handling, ETL | No comments

Thursday, 1 March 2012

WinSCP sFTP Tasks for my SSIS Package Template

Posted on 13:49 by Unknown
I have an SSIS Template package to speed up development. I use WinSCP as an sFTP task as the standard SSIS FTP Task can't do sFTP and all my recent development requirements have specifically asked for sFTP. There are many tools you can use. I like WinSCP because it works well both as an application and from the command line, it's got good online documentation for scripting command line tasks and it's free.

I call WinSCP from an Execute Package Task. This requires an installation on the server where the SSIS package executes - I don't run ETL tasks on a production server but I've found many instances where legacy systems do. I prefer to use a powerful workhorse BI/ETL server where I can guarantee an extensive overnight maintenance window and keep the production environment both secure and dedicated to its primary role.

In my SSIS Template I have a preconfigured PUT and GET task both driven from variables populated from a configuration table in my Metadata database. I could, if required, encrypt the sFTP credentials within the configuration table and then decrypt within the stored procedure that creates the string passed to the variable. But let's not over complicate matters unless we have to.

I build the sFTP command line arguments from variables which are collected from my configuration control table. This table can be amended - if for example an FTP password requires regular changes - without having to change the SSIS package.I feel this is a better solution than using a text file script as the text files then need to be version controlled, secured and backed up. Using a configuration table and SSIS variables allows other benefits such as security, centralisation of control data and the potential to encrypt if required.

I configure the Execute Process Task as shown here.


Below are examples of my SSIS expression and the output it returns.

Get File(s)

Expression - @[User::FTPPrefix] +  @[User::FTPUsername] + ":" +  @[User::FTPPassword] + "@" +  @[User::FTPHost] + "\" \"get " + "\" \"//*.csv \" \"" +  @[User::FTPDestinationFolder] +  @[User::FTPSuffix]

Output - /console /command "option batch on" "option confirm off"  "option transfer binary" "open sftp://username:password@mydomain.ftp.com" "get " "//*.csv " "C:\Temp "close" "exit"

Put File(s)

Expression - @[User::FTPPrefix] +  @[User::FTPUsername] + ":" +  @[User::FTPPassword] + "@" +  @[User::FTPHost] + "\" \"put \"" +  @[User::FTPSourceFolder] +  "InsertFileNameHere" + (DT_STR,4,1252)YEAR(GETDATE()) + RIGHT("0" + (DT_STR,2,1252)MONTH(GETDATE()),2) + RIGHT("0" + (DT_STR,2,1252)DAY(GETDATE()),2) + ".zip" + "\" \"//\"\"" +  @[User::FTPSuffix]

Output - /console /command "option batch on" "option confirm off"  "option transfer binary" "open sftp://username:password@mydomain.ftp.com " "put "\\172.0.0.1\C$\sFTP\InsertFileNameHere20120301.zip" "//"" "close" "exit"

I hope you find this useful. I'll be sharing my full SSIS template shortly. 

UPDATE: Check out my 7-Zip archiving task also used as part of my SSIS package template.
Read More
Posted in Package Template, sFTP, SSIS, WinSCP | No comments
Newer Posts Older Posts Home
Subscribe to: Posts (Atom)

Popular Posts

  • SQL Bad Practice - Hardcoding
    Legacy systems present design challenges different to problems faced during greenfield development. One mistake I've seen time and again...
  • Data Warehousing Resources List
    Listed here are the best resources I've found for learning about data warehousing, useful techniques and methodologies. In no particular...
  • Big Data in the Real World - Part 2 of 2
    Part 1 of this series described the first 2 stages in the processing of clickstream data to allow sales conversion analysis. This post desc...
  • A 7-Zip Archiving Task for my SSIS Package Template
    I use an SSIS package template to speed up project delivery. 7-zip is my archiving tool of choice because it provides encryption and passwor...
  • Book Review - The Checklist Manifesto
    Periodically you read books which change your habits and make you more effective. The Checklist Manifesto is one such book. Authors who can ...
  • Pragmatic Principals - Agile
    The Data Warehouse exists to provide Business Intelligence. Its users will not always start with the end in mind. They will browse, discover...
  • Big Data in the Real World - Part 1 of 2
    There is so much talk of Big Data nowadays, mostly from sales people but also from technologists. Karen Lopez aka DataChick took issue at ...
  • Refactoring Legacy Databases
    Know your enemy - It might not always seem so, but legacy code was written with a process in mind. Determining what the code was originally ...
  • Building an Auditing Process for SSIS - Part 1
    An audit schema published in the excellent book SSIS Problem– Design – Solution allows the efficient capture of SSIS progress and errors in...
  • Pragmatic Principals - Focus
    The DW is a business system not a techie playground. Use Business Analyst's to focus all development on revenue generating (or saving) w...

Categories

  • 7-Zip
  • Architecture
  • Auditing
  • Bad Practice
  • Big Data
  • Book Review
  • Collations
  • Data Cleansing
  • Data Profiling
  • Data Warehouse
  • DBA
  • Design
  • Disaster Recovery
  • Error Handling
  • ETL
  • OLTP
  • Package Template
  • Principals
  • Professional Skills
  • Project Management
  • Quote
  • Refactoring
  • Replication
  • Resources
  • sFTP
  • SQL Agent
  • SSIS
  • T-SQL
  • WinSCP

Blog Archive

  • ►  2013 (8)
    • ►  September (1)
    • ►  July (1)
    • ►  May (2)
    • ►  March (2)
    • ►  February (1)
    • ►  January (1)
  • ▼  2012 (15)
    • ►  December (1)
    • ►  September (1)
    • ►  August (1)
    • ►  July (3)
    • ►  June (2)
    • ►  April (1)
    • ▼  March (2)
      • Easy Error Handling For Data Warehouse Sprocs
      • WinSCP sFTP Tasks for my SSIS Package Template
    • ►  February (3)
    • ►  January (1)
Powered by Blogger.

About Me

Unknown
View my complete profile