Analyze Oracle Listener Log using RingoJS

分析linstener.log(使用RingoJS)

在listener.log中,会记录每一次建立连接的记录,所以在做Oracle 连接相关的问题分析时候,可能需要对listener.log中建立连接的信息进行统计分析。
一些简单的分析需求,可以使用Linux/Unix shell的一些命令行工具来进行,比如grep,wc等,如果想进行一些复杂的分析(某些时间段、某些IP、某些客户端程序建立连接情况),使用perl、ruby之类的脚本语言,配合regular expression,效果也还好;但是做这种类型的分析其实SQL语句是最强大的,此文就介绍一下将listener.log的信息结构化到关系数据库中,然后利用SQL语句进行分析涉及的相关技术。
使用的工具介绍:

  •           RingoJS, javascript解释器,Mozilla使用Java语言实现了一个JavaScript Engine,叫做Rhino,RingoJS是基于Rhino实现的一个工具,常用来和Node.js作对比,都是服务器端JavaScript环境,除了JavaScript语言本身的强大功能外,提供丰富的library,文件IO,网络通讯非常易于实现。
  •           PostgreSQL数据库,Oracle太过庞大了,在我的工作电脑上,已经不再安装Oracle了,PostgreSQL是替代者。
  •           sql-store,RingoJS环境中的ORM组件,用于实现JavaScript对象和关系数据库表的映射。

listener.log的结构:
<TIMESTAMP> * <CONNECT_DATA> * <CLIENT_ADDRESS> * <COMMAND> * <SERVICE_NAME> * <RETURN_CODE>

当然,在listener.log中,也存在其他信息,不符合这个格式,那部分信息我们只是显示出来,不存储到数据库中分析。

RingoJS实现:

var fs = require('fs'); // 使用ringojs fs(Filesystem)组件,来进行文件读写

// 创建到PostgreSQL的数据库连接
var {Store, ConnectionPool} = require("ringo-sqlstore");
var store = exports.store = new Store(new ConnectionPool({
"url":"jdbc:postgresql://localhost:5432/omac",
"driver":"org.postgresql.Driver",
"user":"rattle",
"password":"dswybs"
}));

// 定义JavaScript对象和关系数据库表的对应关系

/*
表名: TnsEntry
字段说明:
occurDate: 连接时间
command: 连接命令,主要是establish
svcName: 服务名
intCode:返回代码, 0 表示成功,
clientHost: 客户端的机器名
clientProgram: 客户端的程序 如果是JDBC,会显示 JDBC THIN之类的
clientIP: 客户端的IP地址
clientUser: 客户端系统的用户名
*/

var TnsEntry = store.defineEntity('TnsEntry',{properties: {
id: {
column: 'entry_id',
type: 'integer',
sequence: 'seq_tnsentry_id'
},
occurDate: {
type: 'timestamp'
},
command: {
type: 'text'
},
svcName: {
type: 'text'
},
intCode: {
type: 'integer'
},
clientHost: {
type: 'text'
},
clientProgram: {
type: 'text'
},
clientIP: {
type: 'text'
},
clientUser: {
type: 'text'
}
}});

// listener.log中有大量 (HOST=A-F15-GBBF9001) 类型字符,提取”HOST=“ 和 “)”之间的字符
var midStrOf = function(str,beginStr,endStr) {

var begPos,endPos;
begPos = str.indexOf(beginStr) + beginStr.length;
endPos = str.indexOf(endStr,begPos);
return str.substring(begPos,endPos);
}

// 打开文件
var file = fs.open('/Users/changzhenghe//listener1112.log');

// 读文件的每一行,进行处理
file.forEach(function(line) {

line = line.trim();
if (!line) {
return;
}
var attrs = line.split('*');

var occurDate,command,svcName,intCode,connData,clientData;
var hostName,clientProgram,clientIP,clientUser;
//console.log('--->'+line);

// 使用regular express进行匹配
if (/service_update/.test(line)) { // Oracle自身的service注册信息记录
[occurDate,command,svcName,intCode] = attrs;
//console.log(' service_update :'+occurDate);
}
else {
[occurDate,connData,clientData,command,svcName,intCode] = attrs;

// 对于一些错误提示信息,只显示,不记录数据库
if (!connData) {
console.log(' ERROR LINE:'+line);
return;
}
if (!clientData) {
console.log(' ERROR LINE:'+line);
return;
}

// JavaScript中缺少将字符串转换成Date类型的方法,使用Java实现
var df = new java.text.SimpleDateFormat('dd-MMM-yyyy HH:mm:ss');
var dtime = df.parse(occurDate).getTime();
var d = new Date(dtime);

// 提取出客户端IP,program,hostname等信息
hostName = midStrOf(connData,'HOST=',')');

clientProgram = midStrOf(connData,'PROGRAM=',')');

clientIP = midStrOf(clientData,'HOST=',')');

clientUser = midStrOf(connData,'USER=',')');
//console.log(clientData) ;
var item = new TnsEntry({
occurDate : d,
command: command||'',
svcName: svcName||'',
intCode: intCode||0,
clientHost: hostName||'',
clientProgram: clientProgram||'',
clientIP: clientIP||'',
clientUser: clientUser||''
});
//console.dir(item);

// 存入数据库
item.save();

}

}) ;

接下来,就可以在数据库中使用SQL,进行各种查询、分析了……

Leave Comment