用过logExplorer的朋友都会被他强悍的功能吸引,我写过一篇详细的操作文档可以参考
http://blog.csdn.net/jinjazz/archive/2008/05/19/2459692.aspx

我们可以自己用开发工具来实现sql日志的读取,这个应用还是很酷的,具体思路

1、首先要了解一个没有公开的系统函数::fn_dblog,他可以读取sql日志,并返回二进制的行数据
2、然后要了解sql的二进制数据是如何存储的,这个可以参考我的blog文章
http://blog.csdn.net/jinjazz/archive/2008/08/07/2783872.aspx
3、用自己擅长的开发工具来分析数据,得到我们需要的信息

我用c#写了一个测试样例,分析了int,char,datetime和varchar的日志情况而且没有考虑null和空字符串的保存,希望感兴趣的朋友能和我一起交流打造属于自己的日志分析工具

详细的试验步骤以及代码如下:

1、首先建立sqlserver的测试环境,我用的sql2005,这个过程不能保证在之前的版本中运行
以下sql语句会建立一个dbLogTest数据库,并建立一张log_test表,然后插入3条数据之后把表清空

  1. usemaster
  2. go
  3. createdatabasedbLogTest
  4. go
  5. usedbLogTest
  6. go
  7. createtablelog_test(idint,codechar(10),namevarchar(20),datedatetime,memovarchar(100))
  8. insertintolog_testselect100,'id001','jinjazz',getdate(),'剪刀'
  9. insertintolog_testselect65549,'id002','游客',getdate()-1,'这家伙很懒,没有设置昵称'
  10. insertintolog_testselect-999,'id003','这家伙来自火星',getdate()-1000,'a'
  11. deletefromlog_test
  12. --usemaster
  13. --go
  14. --dropdatabasedbLogTest

2、我们最终的目的是要找到被我们删掉的数据

3、分析日志的c#代码:我已经尽量详细的写了注释

  1. usingSystem;
  2. usingSystem.Collections.Generic;
  3. usingSystem.Text;
  4. namespaceConsoleApplication21
  5. {
  6. classProgram
  7. {
  8. ///<summary>
  9. ///分析sql2005日志,找回被delete的数据,引用请保留以下信息
  10. ///作者:jinjazz(csdn的剪刀)
  11. ///作者blog:http://blog.csdn.net/jinjazz
  12. ///</summary>
  13. ///<paramname="args"></param>
  14. staticvoidMain(string[]args)
  15. {
  16. using(System.Data.SqlClient.SqlConnectionconn=newSystem.Data.SqlClient.SqlConnection())
  17. {
  18. conn.ConnectionString="server=localhost;uid=sa;pwd=sqlgis;database=dbLogTest";
  19. conn.Open();
  20. using(System.Data.SqlClient.SqlCommandcommand=conn.CreateCommand())
  21. {
  22. //察看dbo.log_test对象的sql日志
  23. command.CommandText=@"SELECTallocunitname,operation,[RowLogContents0]asr0,[RowLogContents1]asr1
  24. from::fn_dblog(null,null)
  25. whereallocunitnamelike'dbo.log_test%'and
  26. operationin('LOP_INSERT_ROWS','LOP_DELETE_ROWS')";
  27. System.Data.SqlClient.SqlDataReaderreader=command.ExecuteReader();
  28. //根据表字段的顺序建立字段数组
  29. Datacolumn[]columns=newDatacolumn[]
  30. {
  31. newDatacolumn("id",System.Data.SqlDbType.Int),
  32. newDatacolumn("code",System.Data.SqlDbType.Char,10),
  33. newDatacolumn("name",System.Data.SqlDbType.VarChar),
  34. newDatacolumn("date",System.Data.SqlDbType.DateTime),
  35. newDatacolumn("memo",System.Data.SqlDbType.VarChar)
  36. };
  37. //循环读取日志
  38. while(reader.Read())
  39. {
  40. byte[]data=(byte[])reader["r0"];
  41. try
  42. {
  43. //把二进制数据结构转换为明文
  44. TranslateData(data,columns);
  45. Console.WriteLine("数据对象{1}的{0}操作:",reader["operation"],reader["allocunitname"]);
  46. foreach(Datacolumncincolumns)
  47. {
  48. Console.WriteLine("{0}={1}",c.Name,c.Value);
  49. }
  50. Console.WriteLine();
  51. }
  52. catch
  53. {
  54. //to-do...
  55. }
  56. }
  57. reader.Close();
  58. }
  59. conn.Close();
  60. }
  61. Console.WriteLine("************************日志分析完成");
  62. Console.ReadLine();
  63. }
  64. //自定义的column结构
  65. publicclassDatacolumn
  66. {
  67. publicstringName;
  68. publicSystem.Data.SqlDbTypeDataType;
  69. publicshortLength=-1;
  70. publicobjectValue=null;
  71. publicDatacolumn(stringname,System.Data.SqlDbTypetype)
  72. {
  73. Name=name;
  74. DataType=type;
  75. }
  76. publicDatacolumn(stringname,System.Data.SqlDbTypetype,shortlength)
  77. {
  78. Name=name;
  79. DataType=type;
  80. Length=length;
  81. }
  82. }
  83. ///<summary>
  84. ///sql二进制结构翻译,这个比较关键,测试环境为sql2005,其他版本没有测过。
  85. ///</summary>
  86. ///<paramname="data"></param>
  87. ///<paramname="columns"></param>
  88. staticvoidTranslateData(byte[]data,Datacolumn[]columns)
  89. {
  90. //我只根据示例写了Char,DateTime,Int三种定长度字段和varchar一种不定长字段,其余的有兴趣可以自己补充
  91. //这里没有暂时没有考虑Null和空字符串两种情况,以后会补充。
  92. //引用请保留以下信息:
  93. //作者:jinjazz
  94. //sql的数据行二进制结构参考我的blog
  95. //http://blog.csdn.net/jinjazz/archive/2008/08/07/2783872.aspx
  96. //行数据从第5个字节开始
  97. shortindex=4;
  98. //先取定长字段
  99. foreach(Datacolumncincolumns)
  100. {
  101. switch(c.DataType)
  102. {
  103. caseSystem.Data.SqlDbType.Char:
  104. //读取定长字符串,需要根据表结构指定长度
  105. c.Value=System.Text.Encoding.Default.GetString(data,index,c.Length);
  106. index+=c.Length;
  107. break;
  108. caseSystem.Data.SqlDbType.DateTime:
  109. //读取datetime字段,sql为8字节保存
  110. System.DateTimedate=newDateTime(1900,1,1);
  111. //前四位1/300秒保存
  112. intsecond=BitConverter.ToInt32(data,index);
  113. date=date.AddSeconds(second/300);
  114. index+=4;
  115. //后四位1900-1-1的天数
  116. intdays=BitConverter.ToInt32(data,index);
  117. date=date.AddDays(days);
  118. index+=4;
  119. c.Value=date;
  120. break;
  121. caseSystem.Data.SqlDbType.Int:
  122. //读取int字段,为4个字节保存
  123. c.Value=BitConverter.ToInt32(data,index);
  124. index+=4;
  125. break;
  126. default:
  127. //忽略不定长字段和其他不支持以及不愿意考虑的字段
  128. break;
  129. }
  130. }
  131. //跳过三个字节
  132. index+=3;
  133. //取变长字段的数量,保存两个字节
  134. shortvarColumnCount=BitConverter.ToInt16(data,index);
  135. index+=2;
  136. //接下来,每两个字节保存一个变长字段的结束位置,
  137. //所以第一个变长字段的开始位置可以算出来
  138. shortstartIndex=(short)(index+varColumnCount*2);
  139. //第一个变长字段的结束位置也可以算出来
  140. shortendIndex=BitConverter.ToInt16(data,index);
  141. //循环变长字段列表读取数据
  142. foreach(Datacolumncincolumns)
  143. {
  144. switch(c.DataType)
  145. {
  146. caseSystem.Data.SqlDbType.VarChar:
  147. //根据开始和结束位置,可以算出来每个变长字段的值
  148. c.Value=System.Text.Encoding.Default.GetString(data,startIndex,endIndex-startIndex);
  149. //下一个变长字段的开始位置
  150. startIndex=endIndex;
  151. //获取下一个变长字段的结束位置
  152. index+=2;
  153. endIndex=BitConverter.ToInt16(data,index);
  154. break;
  155. default:
  156. //忽略定长字段和其他不支持以及不愿意考虑的字段
  157. break;
  158. }
  159. }
  160. //获取完毕
  161. }
  162. }
  163. }

4、更改你的sql连接字符串后运行以上代码,会看到如下输出信息:

  1. 数据对象dbo.log_test的LOP_INSERT_ROWS操作:
  2. id=100
  3. code=id001
  4. name=jinjazz
  5. date=2008-8-718:14:03
  6. memo=剪刀
  7. 数据对象dbo.log_test的LOP_INSERT_ROWS操作:
  8. id=65549
  9. code=id002
  10. name=游客
  11. date=2008-8-618:14:03
  12. memo=这家伙很懒,没有设置昵称
  13. 数据对象dbo.log_test的LOP_INSERT_ROWS操作:
  14. id=-999
  15. code=id003
  16. name=这家伙来自火星
  17. date=2005-11-1118:14:03
  18. memo=a
  19. 数据对象dbo.log_test的LOP_DELETE_ROWS操作:
  20. id=100
  21. code=id001
  22. name=jinjazz
  23. date=2008-8-718:14:03
  24. memo=剪刀
  25. 数据对象dbo.log_test的LOP_DELETE_ROWS操作:
  26. id=65549
  27. code=id002
  28. name=游客
  29. date=2008-8-618:14:03
  30. memo=这家伙很懒,没有设置昵称
  31. 数据对象dbo.log_test的LOP_DELETE_ROWS操作:
  32. id=-999
  33. code=id003
  34. name=这家伙来自火星
  35. date=2005-11-1118:14:03
  36. memo=a
  37. ************************日志分析完成

试验成功~~

用c#读取并分析sql2005日志的更多相关文章

  1. c#读取并分析sql Server2005数据库日志

    用过logExplorer的朋友都会被他强悍的功能吸引,我写过一篇详细的操作文档可以参考http://blog.csdn.net/jinjazz/archive/2008/05/19/2459692. ...

  2. web后门排查与高效分析web日志技巧

    今年一直大大小小的事情忙,很少有时间能静下心写个文章,所以最近博客更新也越来越少了,公司现在安全团队在我这边,一直在玩命的招人.下个月8号有一个互联网金融的会,4月在qcon北京站,都以嘉宾的身份去分 ...

  3. 一天,python搞个分析NGINX日志的脚本

    准备给ZABBIX用的. 统计接口访问字次,平均响应时间,4XX,5XX次数 以后可以再改进.. #!/usr/bin/env python # coding: utf-8 ############# ...

  4. C# 分析 IIS 日志(Log)

    由于最近又要对 IIS日志 (Log) 分析,以便得出各个搜索引擎每日抓取的频率,所以这两天一直在尝试各个办法来分析 IIS 日志 (Log),其中尝试过:导入数据库.Log parser.Powse ...

  5. 利用LogParser分析IIS日志

    LogParser是微软官方出品的用于读取分析IIS日志的工具,使用类SQL语句过滤文本日志内容,并可将内容导出到csv.sqlserver作进一步分析    下载地址:http://www.micr ...

  6. 使用awstats分析nginx日志

    1.awstats介绍 本文主要是记录centos6.5下安装配置awstats,并统计nginx访问日志 1.1 awstats介绍 awstats是一款日志统计工具,它使用Perl语言编写,可统计 ...

  7. 烂泥:利用awstats分析nginx日志

    本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb 昨天把nginx的日志进行了切割,关于如何切割nginx日志,可以查看<烂泥:切割 ...

  8. 用OSSIM轻松分析网络设备日志

    用OSSIM轻松分析网络设备日志 基于插件的日志收集与处理模式,使得用户可以轻松的利用OSSIM来分析异构网络环境下的各种网络设备日志,下面展示一些硬件设备日志的实例,我们在RAW LOG界面里,搜索 ...

  9. Spring AOP在函数接口调用性能分析及其日志处理方面的应用

    面向切面编程可以实现在不修改原来代码的情况下,增加我们所需的业务处理逻辑,比如:添加日志.本文AOP实例是基于Aspect Around注解实现的,我们需要在调用API函数的时候,统计函数调用的具体信 ...

随机推荐

  1. echo二次开发 ecshop 函数列表

    lib_time.php (时间函数) gmtime() P: 获得当前格林威治时间的时间戳 /$0 server_timezone() P: 获得服务器的时区 /$0 local_mktime($h ...

  2. Jedis的JedisSentinelPool源代码分析

    概述 Jedis是Redis官方推荐的Java客户端,更多Redis的客户端可以参考Redis官网客户端列表.Redis-Sentinel作为官方推荐的HA解决方案,Jedis也在客户端角度实现了对S ...

  3. MyGeneration 数据库驱动为空

    重做系统后安装了MyGeneration  但是安装完成后发现驱动中没有驱动信息,查了下网上的解决方案发下下面的可以完美解决,特作备忘: The problem is because of multi ...

  4. python 本地文档查看

    本地安装Python文档本地查看,在命令行中运行: python -m pydoc -p 1234 在浏览器中访问如下链接,就可以访问到本地文档: http://localhost:1234/ 本地文 ...

  5. 关于webpack最好的文档

    这几天研究webpack打包工具,在网上搜了无数的资料,鱼龙混杂.看了几十份资料,依然没有一个可以完整的描述的. 折腾了那么久,还是放弃治疗了.回到官网,一字一句的阅读,一个小时就彻底明白了. 学习新 ...

  6. 【开发流程】土耳其CDD工具

    土耳其的CDD工具开发到现在已经三个星期了,进展非常不顺利,从最开始的遇到很多难题没法解决到现在工具可以运行但是有一个bug. 起初遇到的ExternalUtranCell这一页的信息很难填,没有解决 ...

  7. bzoj 3091 城市旅行(LCT+数学分析)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3091 [思路] 膜Popoqqq大爷的题解 click here [代码]是坑... ...

  8. java 复习003

    今天主要复习下数据结构的东西 树 自平衡二叉查找树 AVL树(高平衡树)(wiki) 特性:任何节点的两个子树的高度最大差别为一 时间复杂度:查找.插入和删除在平均和最坏情况下都是O(log n) 红 ...

  9. jedis连接池详解(Redis)

    转自:http://tianxingzhe.blog.51cto.com/3390077/1684306 原子性(atomicity): 一个事务是一个不可分割的最小工作单位,事务中包括的诸操作要么都 ...

  10. java动态代理与老式AOP实现

    JAVA的动态代理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会 ...