错误捕捉方案

来源:互联网 发布:买淘宝店铺安全吗 编辑:程序博客网 时间:2024/05/16 12:14

 

 

 

 

 

 

 

 

 

 

 

IBMS错误处理改善

设计说明书V1.0

 

 

 

 

 

 

 

 

 

修订历史

 

版本

日期

修改内容

作者

审核人

批准

1.0

2011-03-30

发布

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

1.        概述

1.1     目的

目前IBMS系统后台捕捉错误的信息只有代理或脚本库名称和出错行数,并且是通过描述的方式输出在控制台上,这种方式很不规范,造成了查询、跟踪错误比较困难。为了更好的跟踪IBMS系统发生的错误信息,需要改善目前捕捉错误日志信息的处理方式。

1.2     适用范围

IBMS错误捕捉与处理

1.3     术语表

1-1术语与缩写表

缩写、术语

 

 

 

 

 

2.        架构设计

2.1     基本逻辑图

 

 

系统关系说明:

n 应用数据库:IBMS系统的一个应用库,当用户操作或系统自动处理出现异常错误时,程序的错误捕捉机制获取到错误信息,抛出错误到控制台,并在错误日志库中建立相应文档。

n 错误日志库:IBMS架构下的数据库,为了方便设计,路径固定为“lks/sys/lks_ErrorLog.nsf”。按照一定规则保存所有抛出的异常错误,同时通过代理定时将错误日志导入到关系型数据库中(SQL)

n 关系型数据库:用于长期保存所有的异常错误。

 

3.        错误日志库

3.1     表单设计说明

3.1.1       错误日志

n 表单画面

暂略

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

n 表单字段说明

字段名

Notes字段名

SQL字段名

SQL字段类型

是否必需

描述

错误编号

F_ErrorNo

Error_No

NVARCHAR(50)

控制台显示错误消息时,可以根据错误编号到错误日志库中查询对应文档查看详细错误日志

编号规则:

Err_yymmdd_0001(四位流水号)

错误类型

F_ErrorType

Error_Type

INT

0 -系统捕捉到错误,并且已针对错误进行处理

1 -系统捕捉的未知错误,未对错误进行处理

默认:1

严重程度

F_ErrorLevel

Error_Level

INT

0 -一般(不会对用户造成影响)

1 -严重(可能对用户造成影响,但仅局限于某个用户或单独的应用模块)

2 -非常严重(可能对整个系统造成影响)

默认:1

错误时间

F_ErrorTime

Error_Time

DateTime

发生错误时间

代理名称

F_ErrorAgent

Error_Name

NVARCHAR(255)

发生错误的代理名称

脚本库名称

F_ErrorLibary

Error_Libary

NVARCHAR(50)

发生错误的脚本库名称

函数名称

F_ErrorFunction

Error_Function

NVARCHAR(50)

发生错误的函数名称

错误行数

F_ErrorLine

Error_Line

INT

 

错误代码

F_ErrorCode

Error_Code

INT

 

错误描述

F_ErrorDesc

Error_Desc

NVARCHAR(255)

 

服务器名称

F_ErrorServer

Error_Server

NVARCHAR(50)

发生错误的服务器名称

数据库ID

F_ErrorDBID

Error_DBID

CHAR(32)

发生错误的代理所在数据库ID

数据库路径

F_ErrorDBPath

Error_DBPath

NVARCHAR(255)

发生错误的代理所在数据库路径

处理文档

F_ErrorDocID

Error_DocID

NVARCHAR(255)

发生错误时正在处理的文档ID

处理字段

F_ErrorField

Error_Field

NVARCHAR(50)

发生错误时正在处理的字段名称

当前用户

F_ErrorUser

Error_User

NVARCHAR(50)

发生错误时当前用户名称

当前用户IP

F_ErrorIP

Error_IP

NVARCHAR(50)

发生错误时用户的访问IP地址

当前流程名称

F_ErrorFlow

ErrorFlow

NVARCHAR(100)

发生错误时当前流程名称

当前流程节点

F_ErrorFlowNode

ErrorFlowNode

NVARCHAR(100)

发生错误时当前流程环节

 

3.1.2       系统设定

n 表单画面

暂略

n 表单字段说明

字段名

Notes字段名

Notes字段类型

是否必填

描述

服务器

F_Server

文本

SQL Server服务器名称或ip地址

数据库

F_Database

文本

存放错误日志的数据库名称

表单

F_Form

文本

存放错误日志的表

用户名

F_Login

文本

链接Sql的用户名,需要有写的权限

密码

F_Password

密码

 

 

3.2     代理

代理用于将日志文档定时导入到关系型数据库中。

运行方式:定时运行

运行频率:每周一次

处理方式:从日志库中获取Flag标志不等于“1”的错误日志文档,成功导入到关系型数据库后将文档Flag标志设为“1”。

 

4.        应用库

4.1     错误处理范围

 

错误处理的涉及范围:所有应用库的代理、脚本库。

 

 

4.2     错误处理方案

因原先的错误处理方式多样,没有统一的接口来处理,且经过多次开发后,代码格式也不统一,没法通过程序统一来部署,所以本方案只能采用人工一一部署的方式。

 

(一)旧错误捕捉方式处理

因原先已经存在的错误处理方式多样,且存在量很多。如果一一分析是否需要删除并用新的方案替换,此种方式工作量太大。所以采用原来的错误保持不变,在原先的基础上增加新的处理机制,当出现问题时,只要关注新的错误提示信息即可。

 

(二)新的错误捕捉方式处理

 

n 代码添加的两种方式:

A.    错误冒泡模式,即错误会反映到上层调用者(即引起上层调用者触发错误),如:

序号

部署前代码

部署后代码

描述

1

一般的函数

Sub Sample()

On Error Goto errhandle

代码块

errhandle:

原错误处理块

End Sub

Use "LS_CError"

Sub Sample()

On Error Goto errhandle

代码块

errhandle:

原错误处理块

        Dim cError As New CError(Erl,Err,Error)

Error Err,cError.GetError

End Sub

n "LS_CError"脚本中为错误处理类

n 黄色标记的为新的错误处理方式:

像这种部署前的代码可以看出报错后,错误反映到上层调用者,那么在此sub内就不需要建立错误日志文档和将错误信息输入到服务器控制台,只需要将错误信息手动抛出到上层调用者那即可。

注:部署只要将黄色标记代码添加到合理位置即可

Function Sample()也是如此

2

一般类

Public Class temp

Sub Sample()

On Error Goto errhandle

代码块

errhandle:

原错误处理块

End Sub

End Class

Use "LS_CError"

Public Class temp

Sub Sample()

On Error Goto errhandle

代码块

errhandle:

原错误处理块

        Dim cError As New CError(Erl,Err,Error)

Error Err,cError.GetError

End Sub

End Class

n "LS_CError"脚本中为错误处理类

n 黄色标记的为新的错误处理方式:

像这种部署前的代码可以看出报错后,错误反映到上层调用者,那么在此sub内就不需要建立错误日志文档和将错误信息输入到服务器控制台,只需要将错误信息手动抛出到上层调用者那即可。

注:部署只要将黄色标记代码添加到合理位置即可

Function Sample()也是如此

 

错误描述说明

保存到错误日志库和输出到控制台的错误信息格式为:

ErrorNo_Server_Database_Agent_LotusScript_Function_Error_

示例:

ServerCN=homedev/O=STPDatabasesuntech/sto/lks_MaterialIntroduce.nsfAgent】测试错误日志代理|testLotusScriptTESTSCRIPTFunctionTESTErrorType mismatch(10,13)

Type mismatch(10,13)括号中的第一个表示错误行,第二个表示错误代码

 

B.   错误不冒泡模式,即错误不会反映到上层调用者,如:

序号

部署前代码

部署后代码

描述

1

脚本库

Sub Initialize

On Error Goto errhandle

代码块

errhandle:

原错误处理块

End sub

Use "LS_CError"

Sub Initialize

On Error Goto errhandle

代码块

errhandle:

原错误处理块

Dim cError As New CError(Erl,Err,Error)

cError.ThrowError

End sub

n 黄色标记的为新的错误处理方式:

像这种部署前的代码可以看出报错后,在Initialize错误不会反映到外层,那么在此sub内就需要建立错误日志文档和将错误信息输入到服务器控制台

注:部署只要将黄色标记代码添加到合理位置即可

2

代理

Sub Initialize

On Error Goto errhandle

代码块

errhandle:

原错误处理块

End sub

Use "LS_CError"

Sub Initialize

On Error Goto errhandle

代码块

errhandle:

原错误处理块

Dim cError As New CError(Erl,Err,Error)

cError.ThrowError

End sub

n 黄色标记的为新的错误处理方式:

像这种部署前的代码可以看出报错后,在Initialize错误不会反映到外层,那么在此sub内就需要建立错误日志文档和将错误信息输入到服务器控制台

注:部署只要将黄色标记代码添加到合理位置即可

3

代理和脚本的一般函数

Sub Sample()

On Error Goto errhandle

代码块

Exitfunc:

Exit sub

errhandle:

原错误处理块

Resume exitfunc

End sub

Use "LS_CError"

Sub Sample()

On Error Goto errhandle

代码块

Exitfunc:

Exit sub

errhandle:

原错误处理块

Dim cError As New CError(Erl,Err,Error)

cError.ThrowError

resume exitfunc

End sub

n 黄色标记的为新的错误处理方式:

像这种部署前的代码可以看出报错后,错误不会反映到上层调用者,那么在此sub内就需要建立错误日志文档和将错误信息输入到服务器控制台。

注:部署只要将黄色标记代码添加到合理位置即可

Function Sample()也是如此

 

说明:如果通过exit function/sub的方式结束的话一般不会将错误反映到上层调用者

4

一般函数

Sub Sample()

On Error Goto errhandle

代码块

Exit sub

errhandle:

原错误处理块

Resume next

End sub

n 黄色标记的为新的错误处理方式:

像这种部署前的代码可以看出报错后,错误不会反映到上层调用者,那么在此sub内就需要建立错误日志文档和将错误信息输入到服务器控制台。

注:部署只要将黄色标记代码添加到合理位置即可

Function Sample()也是如此

 

说明:如果通过<FONT style="LINE-HEIGHT: 125%" color="red" face=""">exit function/sub的方式结束的话一般不会将错误反映到上层调用者

 

错误描述说明

保存到错误日志库和输出到控制台的错误信息格式为:

ErrorNo_Server_Database_Agent_LotusScript_Function_Error_Execute Relation_

示例:

ServerCN=homedev/O=STPDatabasesuntech/sto/lks_MaterialIntroduce.nsfAgent】测试错误日志代理|testLotusScriptTESTSCRIPTFunctionTESTErrorType mismatch(10,13)Execute Relation[LS]TESTSCRIPT[Func]TEST1(5)<<[LS]TESTSCRIPT[Func]TEST2(3)<<[LS]DADDC54[Func]INITIALIZE(3)

 

n  Execute Relation】表示错误程序的一个调用关系,关系为代理“测试错误日志代理|test”的INITIALIZE方法调用了方法test2test2调用了test1test1调用了testtest方法报错,将错误信息冒泡到调用层,生成了此错误信息。

n  [LS]TESTSCRIPT[Func] TEST1 (5)表示脚本库TESTSCRIPT的方法TEST1的第5行报错,它调用了test方法

n  [LS]DADDC54[Func]INITIALIZE(3)LSDADDC54时不像一个脚本的名称则表示此LS其实是Agent代号(无法获得代理名,代理名称前面已经通过其他方式获取了,所以不影响)

 

n 可选参数的设置

错误类型、严重程度和处理文档ID、自定义参数(描述看类的方法),4个参数默认情况下可以不需要处理。但有些方法体内报错时有此4个参数中的部分参数需要保存到错误日志时,可以通过CError类的SetOptional成员方法来完成。

如:

Use "LS_CError"

Sub Sample()

On Error Goto errhandle

代码块

Exitfunc:

Exit sub

errhandle:

原错误处理块

Dim cError As New CError(Erl,Err,Error)

Call cError.SetOptional(1,1,cdoc.DocumentUniqueID,"F_ErrorField:1;F_ErrorUser:1;F_ErrorIP:1; F_ErrorFlow:1;F_ErrorFlowNode:1")

cError.ThrowError

resume exitfunc

End sub

 

n 特殊部署说明

在部署过程中,可能有些方法并没有加On Error goto语句来捕捉错误,所以这里可能就不会部署新的错误捕捉机制。当一个方法报错并触发新的错误捕捉机制(错误冒泡模式)时,它的调用链(方法的调用者,一直到代理的Initialize方法)中没有一个方法部署了新的错误捕捉机制,出现的问题为抛出的错误信息未使用类CErrorThrowError方法来处理,那么将不会保存错误信息到错误日志库中,只会抛出如下的错误信息到控制台:

2011-06-29 13:06:41  HTTP Server: Agent '测试错误日志代理(部分无错误处理) test3' error: F_ErrorType:1;F_ErrorLevel:1;F_ErrorDocID:;F_ErrorField:;F_ErrorUser:CN=guangbiao Pan/OU=WuXi/O=STP;F_ErrorIP:1;F_ErrorFlow:1;F_ErrorFlowNode:1*&$#Ser

verCN=homedev/O=STPDatabasesuntech/sto/ErrorTemp.nsfAgent】测试错误日志代理(部分无错误处理) test3LotusScriptTESTSCRIPT3FunctionTESTErrorType mismatch(7,13)

注:错误信息由 类CError的方法GetError产生

A.  解决方法一:在所有代理的Initialize方法中使用新的错误捕捉机制,但可能会无法获得完整的调用链(建议)

B.  解决方法二:不执行解决方法一,让错误只在控制台显示(不建议)

 

 

5.        代码

错误日志类的原代码

'****************************************************
'类名:CError
'描述:记录脚本运行错误,并保存到错误日志库中(lks/sys/lks_ErrorLog.nsf)
'作者:潘广彪
'日期:2011.06.13-2013.11.12
'****************************************************
Public Class CError
 
 '◆定义属性----------------------------------------------------------------------------------
 Public session As NotesSession
 Public cdb As NotesDatabase
 Public cAgent As NotesAgent
 Public errorDb As NotesDatabase     '错误日志库
 
 '==============属性1========================
 Public ErrorLine As Long      '错误行数
 Public ErrorCode As Integer      '错误代码
 Public ErrorDesc As String      '错误描述
 '==============属性2========================
 Public ErrorNo As String      '错误编号:Err_yymmdd_0001(四位流水号)
 Public ErrorTime As NotesDateTime     '错误时间
 Public ErrorServer As String     '服务器名称
 Public ErrorDBID As String      '数据库ID
 Public ErrorDBPath As String     '数据库路径
 Public ErrorAgent As String      '代理名称
 Public ErrorLibary As String     '脚本库名称
 Public ErrorFunction As String     '函数名称
 '==============属性3========================
 Public ErrorType As Integer      '错误类型:
              '0-系统捕捉到错误,并且已针对错误进行处理
              '1 -系统捕捉的未知错误,未对错误进行处理
 Public ErrorLevel As Integer     '严重程度:
              '0- 一般(不会对用户造成影响)
              '1 - 严重(可能对用户造成影响,但仅局限于某个用户或单独的应用模块)
              '2 - 非常严重(可能对整个系统造成影响)
 
 Public ErrorDocID As String      '处理文档ID
 Public SelfDefineParam As String    '自定义参数,在方法SetOptional中详细描述
 
 '●构造方法-----------------------------------------------------------------------------------
 Public Sub New(errorLine As Long,errorCode As Integer,errorDesc As String)
  Me.ErrorLine=errorLine
  Me.ErrorCode=errorCode
  Me.ErrorDesc=errorDesc
  
  ErrorType=1
  ErrorLevel=1
  Set session=New NotesSession
  Set cdb=session.CurrentDatabase
  Set cAgent=session.CurrentAgent  
  Set errorDb=session.GetDatabase(cdb.Server,"lks/sys/lks_ErrorLog.nsf",False)
 End Sub
 
 '●定义方法-----------------------------------------------------------------------------------
 
 '*******************************************
 '方法:抛出错误信息
 '描述:抛出所有错误信息并保存到错误日志库中
 '*******************************************
 Public Sub ThrowError()
  ErrorLibary=Getthreadinfo(11)
  ErrorFunction=Getthreadinfo(10)
  '获取错误信息
  Me.GetError
  '保存错误日志
  Me.save
  '输出错误到控制台
  Me.PrintToConsole
 End Sub
 
 '*******************************************
 '方法:获取错误信息
 '描述:获取所有错误信息并保存到错误日志库中
 '*******************************************
 Public Function GetError()
  ErrorServer=cdb.Server
  ErrorDBID=cdb.Replicaid
  ErrorDBPath=cdb.FilePath
  Set ErrorTime=New NotesDateTime(Now)
  ErrorAgent=cAgent.Name
  If ErrorFunction=""Then
   ErrorLibary=Getthreadinfo(11)
   ErrorFunction=Getthreadinfo(10)
  End If  
  
  GetError=Me.GetErrorDesc
 End Function
 
 '*******************************************
 '方法:保存错误日志
 '描述:保存错误信息到错误日志库中
 '*******************************************
 Private Sub Save()
  If errorDb Is Nothing Then
   Msgbox "错误日志库打开失败..."
  Else
   '保存必要属性
   Dim errDoc As NotesDocument     '错误日志文档
   Set errDoc=errorDb.CreateDocument
   errDoc.Form="FM_ErrorLog" 
   '获取详细错误描述
   Dim fullErrorDesc As String
   Dim errorDesc As String
   fullErrorDesc=Me.GetErrorDesc
   errorDesc=Strright(fullErrorDesc,"*&$#")
   errDoc.F_ErrorDesc=errorDesc
   '从详细错误描述中提取错误行、错误代码、脚本名、函数名
   Dim errorInfo As String
   errorInfo=StrMiddle(errorDesc,"【Error】","【")
   errorInfo=Strright(errorInfo,"(")
   errDoc.F_ErrorLine=Strleft(errorInfo,",")
   errDoc.F_ErrorCode=StrMiddle(errorInfo,",",")")
   errDoc.F_ErrorLibary=StrMiddle(errorDesc,"【LotusScript】","【")
   errDoc.F_ErrorFunction=StrMiddle(errorDesc,"【Function】","【")
   '--------------------------------------------------------
   ErrorNo=GetErrorNo()
   errDoc.F_ErrorNo=ErrorNo
   Dim item As New NotesItem(errDoc,"F_ErrorTime",ErrorTime)
   item.IsSummary=True
   errDoc.F_ErrorServer=ErrorServer
   errDoc.F_ErrorDBID=ErrorDBID
   errDoc.F_ErrorDBPath=ErrorDBPath
   errDoc.F_ErrorAgent=ErrorAgent
   '获取非必要属性
   Dim arrFullErrorDesc As Variant
   arrFullErrorDesc=Split(Strleft(fullErrorDesc,"*&$#"),";")
   arrFullErrorDesc=fulltrim(arrFullErrorDesc)
   Dim i As Integer
   For i=0 To Ubound(arrFullErrorDesc)
    Call errDoc.AppendItemValue(Strleft(arrFullErrorDesc(i),":"),Strright(arrFullErrorDesc(i),":"))
   Next
   Call errDoc.Save(True,False)
  End If
 End Sub
 
 '*******************************************
 '方法:获取详细错误描述
 '描述:将错误信息分类组合显示
 '格式:非必要属性*&$#必要属性+触发错误机制的方法调用链
 '******************************************* 
 Private Function GetErrorDesc() As String
  If Instr(ErrorDesc,"【Server】") <> 0 Then '表示GetErrorDesc的方法已经被执行过至少一次
   '增加触发错误机制所在方法的调用链
   If Instr(ErrorDesc,"【Execute Relation】") <> 0 Then  
    GetErrorDesc=ErrorDesc & |<<[LS]|& ErrorLibary & |[Func]| & ErrorFunction & |(| & ErrorLine & |)|
   Else
    GetErrorDesc=ErrorDesc & |【Execute Relation】| & |[LS]|& ErrorLibary & |[Func]| & ErrorFunction & |(| & ErrorLine & |)|
   End If
  Else  
   '获取非必要属性描述
   Dim optionnalDesc As String
   GetErrorDesc=|F_ErrorType:| & ErrorType & |;F_ErrorLevel:| & ErrorLevel & |;F_ErrorDocID:| & ErrorDocID & |;| & SelfDefineParam
   '获取必要属性描述
   GetErrorDesc=GetErrorDesc & |*&$#| & |【Server】| & ErrorServer &|【Database】| & ErrorDBPath & |【Agent】| & ErrorAgent & |【LotusScript】| & ErrorLibary &_
   |【Function】| & ErrorFunction & |【Error】| & ErrorDesc & |(| & ErrorLine & |,| & ErrorCode & |)|
  End If
  
 End Function
 
 '*******************************************
 '方法:获取错误编号
 '描述:
 '*******************************************
 Private Function GetErrorNo() As String
  Dim profileDoc As NotesDocument
  Dim prefix As String
  Dim no As String
  Set profileDoc=errorDb.GetProfileDocument("SysErrorNo")
  prefix="Err_" & Right(Year(Today),2) & Format(Month(Today),"00") & Format(Day(Today),"00")
  If prefix<>profileDoc.F_Prefix(0)Then
   GetErrorNo= prefix & "0001"
   profileDoc.F_Prefix=prefix
   profileDoc.F_No="0001"
  Else
   no=Format(Int(profileDoc.F_No(0))+1,"0000")
   profileDoc.F_No=no
   GetErrorNo= prefix & no
  End If
  Call profileDoc.Save(True,False)
 End Function
 
 '*******************************************
 '方法:设置多个属性值
 '描述:对部分非必要的属性赋值
 '参数: 
 'selfDefineParam:自定义参数
  '格式:Notes字段名:值;Notes字段名:值;...;Notes字段名:值
  '为了字段统一,提供几个自定义参数的字段名 :
 'F_ErrorField(处理字段),F_ErrorUser(当前用户), F_ErrorIP (当前用户IP),F_ErrorFlow(当前流程名称),F_ErrorFlowNode(当前流程节点)
 '*******************************************
 Public Sub SetOptional(errorType As Integer,errorLevel As Integer,errorDocID As String,selfDefineParam As String)  
  Me.ErrorType=errorType
  Me.ErrorLevel=errorLevel
  Me.ErrorDocID=errorDocID
  Me.SelfDefineParam=selfDefineParam
 End Sub
 
 '*******************************************
 '方法:输出错误信息到控制台
 '描述:
 '*******************************************
 Public Sub PrintToConsole()
  Msgbox |【ErrorNo】| & ErrorNo & Strright(Me.GetErrorDesc,"*&$#")
 End Sub 
 
 '*******************************************
 '方法:截取字符串
 '描述:
 '******************************************* 
 Private Function StrMiddle(sourceStr As String,startStr As String,endStr As String) As String
  Dim returnInfo As Variant
  returnInfo=Evaluate(|@Middle("| & sourceStr & |";"| & startStr & |";"| & endStr & |")|)
  StrMiddle=returnInfo(0)
 End Function
End Class

 

原创粉丝点击