- 案例
- 相关背景
- 负载均衡服务器日志内容(部分):请求的时间(格林威治时间)、请求的Url、请求源IP(客户IP)、重定向的地址(重定向到哪台Web服务器)
- Web服务器日志内容(部分):请求的时间(本地时间)、请求的Url,请求源IP(负载均衡服务器IP)
- 监控服务器每五分钟请求一次负载均衡服务器(请求的页面是固定的),用于判定服务器运行是否正常(可以使用这个请求作为对齐标志来匹配日志信息)
- 负载均衡服务器的日志顺序与IIS日志的顺序不一定匹配,例如在负载均衡服务器上的日志顺序为RequestA、RequestB,在IIS日志中的顺序有可能为RequestA、RequestB也有可能为RequesB、RequestA。
- 补充说明
- 假定日志的匹配算法已经解决。
- 日志的处理结果需要保存到三个日志文件中:匹配的、未匹配以及被拦截的(负载均衡服务器拦截的),这三个日志文件的的格式不一定相同。
- 案例行为(Act)整理
- 日志处理活动图(日志处理的活动顺序不一定相同)
- 行为(Act)分析
简单的分析一下,发现要实现匹配日志条目这个处理过程至少需要包含以下两个动作序列:合并两个IIS日志,将IIS日志与负载均衡服务器日志合并,并且合并日志条目这个处理过程包含了读取日志条目的处理过程。也就是说从逻辑层次角度看来,匹配日志条目的层次比读取日志条目的层次要高,以下的图示很清楚的说明了这个问题(两个图分别说明了两种不同的处理方式):
- 能够很自然的贴合用例,便于跟踪需求与设计之间的关系
- 自顶向下的分析方式符合大多数人的习惯
- 抽象的层次清楚,易于理解和使用
- 抽象了行为很自然的符合面向对象的依赖导致原则
- 基于实际需求场景的行为分析,容易保证抽象符合单一职责原则
提取抽象的过程其实就是建模的过程,我们建立一个模型之后,也需要跟写代码一样需要进行测试,对于模型的测试可以通过各种场景(在面向对象中就是用例)来进行测试,看模型是否能够通过所有的应用场景。下面为场景的测试例子(在本例中使用时序图做为测试方法):
![](https://www.cnblogs.com/images/cnblogs_com/zengezenge/ModelTest.JPG)
在测试通过之后就可以很容易的做设计了,以下为类设计的代码(如果熟悉设计模式的话,可以看出来这个地方引入了装饰模式):
1 /// <summary>
2 /// 描述日志列的信息
3 /// </summary>
4 public class LogField
5 {
6 }
7
8 /// <summary>
9 /// 描述了日志行的信息
10 /// </summary>
11 public class LogRow
12 {
13 }
14
15 /// <summary>
16 /// 日志源
17 /// </summary>
18 public interface ILogSource
19 {
20 /// <summary>
21 /// 源日志列定义信息
22 /// </summary>
23 System.Collections.Generic.ICollection<LogField> Fields;
24
25 /// <summary>
26 /// 当前的日志行
27 /// </summary>
28 LogRow CurrentRow;
29
30 /// <summary>
31 /// 读取日志行
32 /// </summary>
33 /// <returns>读取结束的时候返回False</returns>
34 bool ReadLogRow();
35 }
36
37 /// <summary>
38 /// 日志输出
39 /// </summary>
40 public interface ILogOutput
41 {
42 /// <summary>
43 /// 目标日志的定义信息
44 /// </summary>
45 System.Collections.Generic.ICollection<LogField> Fields;
46
47 /// <summary>
48 /// 写入日志信息
49 /// </summary>
50 /// <param name="row"></param>
51 void WriteLogRow(LogRow row);
52 }
根据日志合并的要求需要引入以下的几个类:2 /// 描述日志列的信息
3 /// </summary>
4 public class LogField
5 {
6 }
7
8 /// <summary>
9 /// 描述了日志行的信息
10 /// </summary>
11 public class LogRow
12 {
13 }
14
15 /// <summary>
16 /// 日志源
17 /// </summary>
18 public interface ILogSource
19 {
20 /// <summary>
21 /// 源日志列定义信息
22 /// </summary>
23 System.Collections.Generic.ICollection<LogField> Fields;
24
25 /// <summary>
26 /// 当前的日志行
27 /// </summary>
28 LogRow CurrentRow;
29
30 /// <summary>
31 /// 读取日志行
32 /// </summary>
33 /// <returns>读取结束的时候返回False</returns>
34 bool ReadLogRow();
35 }
36
37 /// <summary>
38 /// 日志输出
39 /// </summary>
40 public interface ILogOutput
41 {
42 /// <summary>
43 /// 目标日志的定义信息
44 /// </summary>
45 System.Collections.Generic.ICollection<LogField> Fields;
46
47 /// <summary>
48 /// 写入日志信息
49 /// </summary>
50 /// <param name="row"></param>
51 void WriteLogRow(LogRow row);
52 }
1 /// <summary>
2 /// 日志合并日志源,用于处理两个日志之间的Union
3 /// </summary> 4 public class LogUnionSource : ILogSource
5 {
6 }
7
8 /// <summary>
9 /// 日志Merge日志源,用于处理两个日志源之间的Merge
10 /// </summary>
11 public class LogMergeSource : ILogSource
12 {
13 }
2 /// 日志合并日志源,用于处理两个日志之间的Union
3 /// </summary> 4 public class LogUnionSource : ILogSource
5 {
6 }
7
8 /// <summary>
9 /// 日志Merge日志源,用于处理两个日志源之间的Merge
10 /// </summary>
11 public class LogMergeSource : ILogSource
12 {
13 }
对于日志字段数据的处理可以将逻辑放入到不同的字段类中。
由于这一阵子事情比较多,暂时就写到这里了。
相关随笔:
由于这一阵子事情比较多,暂时就写到这里了。
相关随笔:
另外补充一点:
使用地方的处理代码,从以下的代码可以看出这样设计和容易利用IOC框架或者配置驱动:
使用地方的处理代码,从以下的代码可以看出这样设计和容易利用IOC框架或者配置驱动:
1 //创建IIS合并日志源
2 dim iisLogSource As LogUnionSource = new LogUnionSource ( new SimpleTextLogSource( IIS1 ),new SimpleTextLogSource( IIS2 ) )
3
4 //创建合并日志源
5 dim arrayLogSource as LogMergeSource = new LogMergeSource( iisLogSource, new SimpleTextLogSource( 防火墙日志 ))
6
7 //创建日志输出
8 dim logOutput as SimpleTextLogOutput = new SimpleTextLogOutput( FileName& nbsp;);
9
10 //写入日志
11 while arrayLogSource.ReadLogRow
12
13 //写入日志条目
14 logOutput.WriteLogRow( arrayLogSource.CurrentRow )
15 end while
2 dim iisLogSource As LogUnionSource = new LogUnionSource ( new SimpleTextLogSource( IIS1 ),new SimpleTextLogSource( IIS2 ) )
3
4 //创建合并日志源
5 dim arrayLogSource as LogMergeSource = new LogMergeSource( iisLogSource, new SimpleTextLogSource( 防火墙日志 ))
6
7 //创建日志输出
8 dim logOutput as SimpleTextLogOutput = new SimpleTextLogOutput( FileName& nbsp;);
9
10 //写入日志
11 while arrayLogSource.ReadLogRow
12
13 //写入日志条目
14 logOutput.WriteLogRow( arrayLogSource.CurrentRow )
15 end while