1、提高系统开关机速度(我请求参数的系统是XP,测试好使,别的系统我可没试过,呵呵!)
英雄联盟cls脚本教程 英雄联盟lua脚本
英雄联盟cls脚本教程 英雄联盟lua脚本
要是有这种东西……电脑就不用[x] 持续集成换新的了……
不过可以用360安全卫士,高级--启动项状态,把开机启动的乱七八糟软件都禁用掉,电脑会快一点。
重装一遍系统会让 = join(self.base_, '')电脑达到速度……不过估计你不会……网上找个教程学学吧
1、提高系统开关机速度(我的系统是XP,测下面使用flask实现两个接口,一个登录,另外一个查询详情,但需要登录后才可以,新建一个demo.py文件(注意,不要使用windows记事本),把下面代码copy进去,然后保存、关闭。试好使,别的系统我可没试过,呵呵!)
要是有这种东西……电脑就不用换新的了……
不过可以用360安全卫士,高级-PARAMETER=$1-启动项状态,把开机启动的乱七八糟软件都禁用掉,电脑会快一点。
重装一遍系统会让电脑达到速度……cls.password = '123456'不过估计你不会……网上找个教程学学吧
删除 %windir%32目录下的wscript.exe 和 cscript.exe
脚本实现在原位置创建2个与之同名的文件夹(设为只读)
= join(self.base_, '')把wscript.exe禁用就是
参考下面的即可:
一、
本文从一个简单的登录接口测试入手,一步步调整优化接口调用姿势,然后简单讨论了一下接口测试框架的要点,介绍了一下我们目前正在使用的接口测试框架pithy。期望读者可以通过本文对接口自动化测试有一个大致的了解。
二、引言
为什么要做接口自动化测试?
在当前互联网产品迭代频繁的背景下,回归测试的时间越来越少,很难在每个迭代都对所有功能做完整回归。但接口自动化测试因其实现简单、维护成本低,容易提高覆盖率等特点,越来越受重视。
为什么要自己写框架呢?
使用requets + unittest很容易实现接口自动化测试,而且requests的api已经非常人性化,非常简单,但通过封装以后(特别是针对公司内特定接口),再加上对一些常用工具的封装,可以进一步提高业务脚本编写效率。
三、环境准备
确保本机已安装python2.7以上版本,然后安装如下库:
pip install flask
pip install requests12
四、测试接口准备
接口代码
#!/usr/bin/python# coding=utf-8from flask import Flask, request, session, jsonify
USERNAME = 'admin'PASSWORD = '123456'app = Flask(__name__)
app.secret_key = 'pithy'@app.route('/login', mods=['GET', 'POST'])def login():
if request.mod == 'POST': if request.form['username'] != USERNAME:
error = 'Invalid username'
elif request.form['password'] != PASSWORD:
error = 'Invalid password'
else:
session['logged_in'] = True
return jsonify({'code': 200, 'msg': 'success'}) return jsonify({'code': 401, 'msg': error}), 401@app.route('/', mods=['get'])def ():
if not session.get('logged_in'): return jsonify({'code': 401, 'msg': 'please login !!'}) return jsonify({'code': 200, 'msg': 'success', 'data': ''})if __name__ == '__main__':
app.run(debug=True)123456780111213141516171819202122232425262728293031323334
执行如下命令:
python demo.py1
响应如下:
Running on (Press CTRL+C to quit)
Restarting with stat12
大家可以看到服务已经起来了。
登录接口
请求
/login
请求方法
t
参数名称
参数类型
参数说明
username String 登录名称
password String 登录密码
响应信息
参数名称
参数类型
参数说明
code Integer 结果code
msg String 结果信息
详情接口
请求
/
请求方法
get
请求cookies
参数名称
参数类型
参数说明
session String session
响应信息
参数名称
参数类型
参数说明
code Integer 结果code
msg String 结果信息
data String 数据信息
五、编写接口测试
测试思路
使用requests [使用链接] 库模拟发送HTTP请求。
使用python标准库里unittest写测试case。
#!/usr/bin/python# coding=utf-8import requestsimport unittestclass TestLogin(unittest.TestCase):
@clasod
def setUpClass(cls):
cls.login_ = ''
cls._ = ''
cls.username = 'admin'
测试登录
}response = requests.t(self.login_, data=data).json() assert response['code'] == 200
assert response['msg'] == 'success'
def test_(self)接口信息:
}response_cookies = requests.t(self.login_, data=data).cookies
session = response_cookies.get('session') assert session
_cookies = { 'session': session
}response = requests.get(self._, cookies=_cookies).json() assert response['code'] == 200
assert response['msg'] == 'success'
assert response['data'] == ''12345678011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
六、优化
封装接口调用
写完这个测试登录脚本,你或许会发现,在整个项目的测试过程,登录可能不止用到一次,如果每次都这么写,会不会太冗余了? 对,确实太冗余了,下面做一下简单的封装,把登录接口的调用封装到一个方法里,把调用参数暴漏出来,示例脚本如下:
#!/usr/bin/python# coding=utf-8import requestsimport unittesttry: from parse import joinexcept ImportError: from lib.parse import joinclass DemoApi(object):
def __init__(self, base_):
self.base_ = base_ def login(self, username, password):
登录接口
:param username: 用户名
:param password: 密码
= join(self.base_, 'login')
data = { 'username': username, 15-JAN-2015 23:51:03 serv_update EPPS 0 'password': password
} return requests.t(, data=data).json() def get_cookies(self, username, password):
获取登录cookies
= join(self.base_, 'login')
data = { 'username': username, 'password': password
} return requests.t(, data=data).cookies def (self, cookies):
详情接口
= join(self.base_, '') return requests.get(, cookies=cookies).json()class TestLogin(unittest.TestCase):
@clasod
def setUpClass(cls):
cls.base_ = ''
cls.username = 'admin'
cls.app = DemoApi(cls.base_) def test_login(self):
测试登录
response = self.app.login(self.username, self.password) assert response['code'] == 200
assert response['msg'] == 'success'
def test_(self):
测试获取详情信息
cookies = self.app.get_cookies(self.username, self.password)
response = self.app.(cookies) assert response['code'] == 200
assert response['msg'] == 'success'
assert response['data'] == ''123456780111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
OK,在这一个版本中,我们不但在把登录接口的调用封装成了一个实例方法,实现了复用,而且还把host(self.base_)提取了出来,但问题又来了,登录之后,登录接口的响应会把session以 cookie的形式set到客户端,之后的接口都会使用此session去请求,还有,就是在接口调用过程中,希望可以把日志打印出来,以便调试或者出错时查看。
好吧,我们再来改一版。
保持cookies&增加log信息
使用requests库里的同一个Session对象(它也会在同一个Session 实例发出的所有请求之间保持 cookie),即可解决上面的问题,示例代码如下:
#!/usr/bin/python# coding=utf-8import unittestfrom pprint import pprintfrom requests.sessions import Sessiontry: from parse import joinexcept ImportError: from lib.parse import joinclass DemoApi(object):
def __init__(self, base_):
self.base_ = base_ # 创建session实例
self.session = Session() def login(self, username, password):
登录接口
:param username: 用户名
:param password: 密码
= join(self.base_, 'login')
data = { 'username': username, 'password': password
}response = self.session.t(, data=data).json()
print('
')
print(u'
1、请求:
%s'# background_dump_dest % )
print(u'
2、请求头信息:')
print(u'
3、请求参数:')
pprint(data)
print(u'
4、响应:')
pprint(response) return response def (self):
详情接口
response = self.session.get().json()
print('
')
print(u'
1、请求:
%s' % )
print(u'
2、请求头信息:')
print(u'
3、请求cookies:')
pprint(dict(self.session.cookies))
print(u'
4、响应:')
pprint(response) return responseclass TestLogin(unittest.TestCase):
@clasod
def setUpClass(cls):
cls.base_ = ''
cls.username = 'admin'
cls.app = DemoApi(cls.base_) def test_login(self):
测试登录
response = self.app.login(self.username, self.password) assert response['code'] == 200
assert response['msg'] == 'success'
def test_(self):
测试获取详情信息
self.app.login(self.username, self.password)
response = self.app.() assert response['code'] == 200
assert response['msg'] == 'success'
assert response['data'] == ''1234567801112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
大功告成,我们把多个相关接口调用封装到一个类中,使用同一个requests Session实例来保持cookies,并且在调用过程中打印出了日志,我们所有目标都实现了,但再看下脚本,又会感觉不太舒服,在每个方法里,都要写一遍print 1、2、3… 要拼、还要很多细节等等,但其实我们真正需要做的只是拼出关键的参数(参数、body参数或者传入headers信息),可不可以只需定义必须的信息,然后把其它共性的东西都封装起来呢,统一放到一个地方去管理?
封装重复作
来,我们再整理一下我们的需求:
首先,不想去重复做拼接的作。
然后,不想每次都去手工打印日志。
不想和requests session打交道。
只想定义好参数就直接调用。
我们先看一下实现后,脚本可能是什么样:
class DemoApi(object):
def __init__(self, base_):
def login(self, username, password):
登录接口
data = { 'username': username, 'password': password
} return {'data': data} @request(='', mod='get')
def (self):
详情接口
pass12345678011121314151617181920212223
调用登录接口的日志:
1、接口描述
登录接口2、请求://127.0.0.1:5000/login3、请求方法t4、请求headers
{ "Accept": "/", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", "User-Agent": "python-requests/2.7.0 CPython/2.7.10 Darwin/16.4.0"}5、body参数
{ "password": "123456", "username": "admin"}6、响应结果
{ "code": 200, "msg": "success"}1234567801112131415161718192021222324252627282930
在这里,我们使用python的装饰器功能,把公共特性封装到装饰器中去实现。现在感觉好多了,没什么多余的东西了,我们可以专注于关键参数的构造,剩下的就是如何去实现这个装饰器了,我们先理一下思路:
获取装饰器参数
获取函数/方法参数
把装饰器和函数定义的参数合并
拼接
处理requests session,有则使用,无则新生成一个
组装所有参数,发送请求并打印日志
因篇幅限制,源码不再列出,有兴趣的同学可以查看已经实现的源代码。
源代码查看地址:
七、扩展
接口请求的姿势我们定义好了,我们还可以做些什么呢?
[x] 非HTTP协议接口
[x] 测试用例编写
[x] 配置文件管理
[x] 测试数据管理
[x] 工具类编写
[x] 测试报告生成
[x] 等等等等
需要做的还是挺多的,要做什么不要做什么,或者先做哪个,我觉得可以根据以下几点去判断:
是否有利于提高团队生产效率?
一、
本文从一个简单的登录接口测试入手,一步步调整优化接口调用姿势,然后简单讨论了一下接口测试框架的要点,介绍了一下我们目前正在使用的接口测试框架pithy。期望读者可以通过本文对接口自动化测试有一个大致的了解。
二、引言
为什么要做接口自动化测试?
在当前互联网产品迭代频繁的背景下,回归测试的时间越来越少,很难在每个迭代都对所有功能做完整回归。但接口自动化测试因其实现简单、维护成本低,容易提高覆盖率等特点,越来越受重视。
为什么要自己写框架呢?
使用requets + unittest很容易实现接口自动化测试,而且requests的api已经非常人性化,非常简单,但通过封装以后(特别是针对公司内特定接口),再加上对一些常用工具的封装,可以进一步提高业务脚本编写效率。
三、环境准备
确保本机已安装python2.7以上版本,然后安装如下库:
pip install flask
pip install requests12
四、测试接口准备
接口代码
#!/usr/bin/python# coding=utf-8from flask import Flask, request, session, jsonify
USERNAME = 'admin'PASSWORD = '123456'app = Flask(__name__)
app.secret_key = 'pithy'@app.route('/login', mods=['GET', 'POST'])def login():
if request.mod == 'POST': if request.form['username'] != USERNAME:
error = 'Invalid username'
elif request.form['password'] != PASSWORD:
error = 'Invalid password'
else:
session['logged_in'] = True
return jsonify({'code': 200, 'msg': 'success'}) return jsonify({'code': 401, 'msg': error}), 401@app.route('/', mods=['get'])def ():
if not session.get('logged_in'): return jsonify({'code': 401, 'msg': 'please login !!'}) return jsonify({'code': 200, 'msg': 'success', 'data': ''})if __name__ == '__main__':
app.run(debug=True)123456780111213141516171819202122232425262728293031323334
执行如下命令:
python demo.py1
响应如下:
Running on (Press CTRL+C to quit)
Restarting with stat12
大家可以看到服务已经起来了。
登录接口
请求
/login
请求方法
t
参数名称
参数类型
参数说明
username String 登录名称
password String 登录密码
响应信息
参数名称
参数类型
参数说明
code Integer 结果code
msg String 结果信息
详情接口
请求
/
请求方法
get
请求cookies
参数名称
参数类型
参数说明
session String session
响应信息
参数名称
参数类型
参数说明
code Integer 结果code
msg String 结果信息
data String 数据信息
五、编写接口测试
测试思路
使用requests [使用链接] 库模拟发送HTTP请求。
使用python标准库里unittest写测试case。
#!/usr/bin/python# coding=utf-8import requestsimport unittestclass TestLogin(unittest.TestCase):
@clasod
def setUpClass(cls):
cls.login_ = ''
cls._ = ''
cls.username = 'admin'
测试登录
}response = requests.t(self.login_, data=data).json() assert response['code'] == 200
assert response['msg'] == 'success'
def test_(self):
}response_cookies = requests.t(self.login_, data=data).cookies
session = response_cookies.get('session') assert session
_cookies = { 'session': session
}response = requests.get(self._, cookies=_cookies).json() assert response['code'] == 200
assert response['msg'] == 'success'
assert response['data'] == ''12345678011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
六、优化echo "ERROR: Number of days is invalid."
封装接口调用
写完这个测试登录脚本,你或许会发现,在整个项目的测试过程,登录可能不止用到一次,如果每次都这么写,会不会太冗余了? 对,确实太冗余了,下面做一下简单的封装,把登录接口的调用封装到一个方法里,把调用参数暴漏出来,示例脚本如下:
#!/usr/bin/python# coding=utf-8import requestsimport unittesttry: from parse import joinexcept ImportError: from lib.parse import joinclass DemoApi(object):
def __init__(self, base_):
self.base_ = base_ def login(self, username, password):
登录接口
:param username: 用户名
:param password: 密码
= join(self.base_, 'login')
data = { 'username': username, 'password': password
} return requests.t(, data=data).json() def get_cookies(self, username, password):
获取登录cookies
= join(self.base_, 'login')
data = { 'username': username, 'password': password
} return requests.t(, data=data).cookies def (self, cookies):
详情接口
= join(self.base_, '') return requests.get(, cookies=cookies).json()class TestLogin(unittest.TestCase):
@clasod
def setUpClass(cls):
cls.base_ = ''
cls.username = 'admin'
cls.app = DemoApi(cls.base_) def test_login(self):
测试登录
response = self.app.login(self.username, self.password) assert response['code'] == 200
assert response['msg'] == 'success'
def test_(self):
测试获取详情信息
cookies = self.app.get_cookies(self.username, self.password)
response = self.app.(cookies) assert response['code'] == 200
assert response['msg'] == 'success'
assert response['data'] == ''123456780111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
OK,在这一个版本中,我们不但在把登录接口的调用封装成了一个实例方法,实现了复用,而且还把host(self.base_)提取了出来,但问题又来了,登录之后,登录接口的响应会把session以 cookie的形式set到pprint(self.session.headers)客户端,之后的接口都会使用此session去请求,还有,就是在接口调用过程中,希望可以把日志打印出来,以便调试或者出错时查看。
好吧,我们再来改一版。
保持cookies&增加log信息
使用requests库里的同一个Session对象(它也会在同一个Session 实例发出的所有请求之间保持 cookie),即可解决上面的问题,示例代码如下:
#!/usr/bin/python# coding=utf-8import unittestfrom pprint import pprintfrom requests.sessions import Sessiontry: from parse import joinexcept ImportError: from lib.parse import joinclass DemoApi(object):
def __init__(self, base_):
self.base_ = base_ # 创建session实例
self.session = Session() def login(self, username, password):
登录接口
:param username: 用户名
:param password: 密码
= join(self.base_, 'login')
data = { 'username': username, 'password': password
}response = self.session.t(, data=data).json()
print('
')
print(u'
1、请求:
%s' % )
print(u'
2、请求头信息:')
print(u'
3、请求参数:')
pprint(data)
print(u'
4、响应:')
pprint(response) return response def (self):
详情接口
response = self.session.get().json()
print('
')
print(u'
1、请求:
%s' % )
print(u'
2、请求头信息:')
print(u'
3、请求cookies:')
pprint(dict(self.session.cookies))
print(u'
4、响应:')
pprint(response) return responseclass TestLogin(unittest.TestCase):
@clasod
def setUpClass(cls):
cls.base_ = ''
cls.username = 'admin'
cls.app = DemoApi(cls.base_) def test_login(self):
测试登录
response = self.app.login(self.username, self.password) assert response['code'] == 200
assert response['msg'] == 'success'
def test_(self):
测试获取详情信息
self.app.login(self.username, self.password)
response = self.app.() assert response['code'] == 200
assert response['msg'] == 'success'
assert response['data'] == ''1234567801112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
大功告成,我们把多个相关接口调用封装到一个类中,使用同一个requests Session实例来保持cookies,并且在调用过程中打印出了日志,我们所有目标都实现了,但再看下脚本,又会感觉不太舒服,在每个方法里,都要写一遍print 1、2、3… 要拼、还要很多细节等等,但其实我们真正需要做的只是拼出关键的参数(参数、body参数或者传入headers信息),可不可以只需定义必须的信息,然后把其它共性的东西都封装起来呢,统一放到一个地方去管理?
封装重复作
来,我们再整理一下我们的需求:
首先,不想去重复做拼接的作。
然后,不想每次都去手工打印日志。
不想和requests session打交道。
只想定义好参数就直接调用。
我们先看一下实现后,脚本可能是什么样:
class DemoApi(object):
def __init__(self, base_):
def login(self, username, password):
登录接口
data = { 'username': username, 'password': password
} return {'data': data} @request(='', mod='get')
def (self):
详情接口
pass12345678011121314151617181920212223
调用登录接口的日志:
1、接口描述
登录接口2、请求://127.0.0.1:5000/login3、请求方法t4、请求headers
{ "Accept": "/", "Accept-Encoding": "gzip, deflate", "Connection": "keep-alive", "User-Agent": "python-requests/2.7.0 CPython/2.7.10 Darwin/16.4.0"}5、body参数
{ "password": "123456", "username": "admin"}6、响应结果
{ "code": 200, "msg": "success"}1234567801112131415161718192021222324252627282930
在这里,我们使用python的装饰器功能,把公共特性封装到装饰器中去实现。现在感觉好多了,没什么多余的东西了,我们可以专注于关键参数的构造,剩下的就是如何去实现这个装饰器了,我们先理一下思路:
获取装饰器参数
获取函数/方法参数
把装饰器和函数定义的参数合并
拼接
处理requests session,有则使用,无则新生成一个
组装所有参数,发送请求并打印日志
因篇幅限制,源码不再列出,有兴趣的同学可以查看已经实现的源代码。
源代码查看地址:
七、扩展
接口请求的姿势我们定义好了,我们还可以做些什么呢?
[x] 非HTTP协议接口
[x] 测试用例编写
[x] 配置文件管理
[x] 测试数据管理
[x] 工具类编写
[x] 测试报告生成
[x] 等等等等
需要做的还是挺多的,要做什么不要做什么,或者先做哪个,我觉得可以根据以下几点去判断:
是否有利于提高团队生产效率?
你可以将BAT脚本转换成Shell脚本(.sh)如下所示:
data = { 'username': self.username, 'password': self.password```bash
15-JAN-2015 23:28:01 serv_update EPPS 0#!/bin/bash
echo "程序正在启动中.."
CLSNAME="macs_tool20.mytools.macs.ui.basedata.Main"
CLSPATH=""
for jarfile in lib.jar
do
CLSPATH="$CLSPATH:$jarfile"
done
ja -Xms128M -Xmx512M -cp .:$CLSPATH $CLSNAME
```
这个Shell脚本将完成与原始BAT脚本相同的任务,包括设置`CLSNAME`和`CLSPATH`,然后运行Ja应用程序。不过请注意,Shell脚本中使用`:`而不是`;`来分隔类路径,并且`$`符号用于引用变量。此外,我们添加了一个Shebang(`#!/bin/bash`)以指示这是一个Bash脚本。
当然要对日志文件(listener.log)进行定期清理,如果不定期清理,会遇到下面一些麻烦:
self.base_ = base_ @request(='login', mod='t')1:日志文件(listener.log)变得越来越大,占用额外的存储空间。(当然现在存储白菜价,不那几G的空间。但是我们还是要本着工匠情怀,精益求精)
2:日志文件(listener.log)变得太大会带来一些问题:LISTENER.LOG日志大小不能超过2GB,超过会导致LISTENER无法处理新的连接。
3:日志文件(listener.log)变得太大,给写入、查看带来的一些性能问题、麻烦。
也有人说是服务进程一般使用标准C函数Write写出到Listener.log,listener.log文件时使用的是O_WRONLY|O_CREAT|O_APPEND,O_APPEND即追加到文件的尾端,一般来说追加写方式不会因为文件越大写地越慢。撇开这个不谈,在一个很大的日志文件(listener.log)查找某一天或某一个错误,这个确实会带来一些性能问题。查找起来也相当麻烦。
所以应该定期对日志文件(listener.log)进行清理,另外一种说法叫截断日志文件。关于截断日志,要注意一些问题。初学ORACLE的时候遇到一个错误的截断日志的,下面演示一下
[oracle@DB- log]$ mv listener.log listener.log.20150114
[oracle@DB- log]$ cp /dev/null listener.log
[oracle@DB- log]$ more listener.log
如上所示,这样截断日志(listener.log)后,服务进程(tnslsnr)并不会将新的信息写入listener.log,而是继续写入listener.log.20150114
[oracle@DB- log]$ tail listener.log.20150114
15-JAN-2015 22:47:59 serv_update EPPS 0
15-JAN-2015 22:58:00 serv_update EPPS 0
15-JAN-2015 23:08:00 serv_update EPPS 0
15-JAN-2015 23:18:01 serv_update EPPS 0
15-JAN-2015 23:38:02 serv_update EPPS 0
15-JAN-2015 2# Usage function.3:41:02 serv_update EPPS 0
15-JAN-2015 23:50:26 ping 0
[oracle@DB- log]$ tail listener.log.20150114
15-JAN-2015 23:18:01 serv_update EPPS 0
15-JAN-2015 23:38:02 serv_update EPPS 0
15-JAN-2015 23:41:02 serv_update EPPS 0
15-JAN-2015 23:50:26 ping 0
15-JAN-2015 23:57:40 ping 0
15-JAN-2015 23:57:41 ping 0
15-JAN-2015 23:57:42 ping 0
15-JAN-2015 23:57:43 ping 0
[oracle@DB- log]$ more listener.log
[oracle@DB- log]$
规范正确的流程应该这么处理:
Step 1:首先停止服务进程(tnslsnr)记录日志。
[oracle@DB- log]$ lsnrctl set log_status off;
LSNRCTL for Linux: Version 10.2.0.4.0 - Production on 16-JAN-2015 00:02:59
Copyright (c) 19, 2007, Oracle. All rights reserved.
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.9.15)(PORT=1521)))
LISTENER parameter "log_status" set to OFF
The command completed successfully
Step 2:将日志文件(listener.log)一份,以listener.log.yyyymmdd格式命名
[oracle@DB- log]$ cp listener.log listener.log.20150114
Step 3:将日志文件(listener.log)清空。清空文件的方法有很多
3.1 echo “” > filename
3.2 cp /dev/null 或 echo /dev/null > filename
Step 4:开启服务进程(tnslsnr)记录日志
[oracle@DB- log]$ lsnrctl set log_status on;
当然也可以移走日志文件(listener.log),数据库实例会自动创建一个listener.log文件。
% lsnrctl set log_status off
% mv listener.log listener.yyyymmdd
% lsnrctl set log_status on
当然这些作应该通过shell脚本来处理,然后结合crontab作业定期清理、截断日志文件。例如网上的一个清理、截断日志文件的shell脚本。
rq=` date +"%d" `
cp $ORACLE_HOME/network/log/listener.log $ORACLE_BACKUP/network/log/listener_$rq.log
cp /dev/null $ORACLE_HOME/network/log/listener.log
su - oracle -c "lsnrctl set log_status on"
这样的脚本还没有解决一个问题,就是截断的日志文件保留多久的问题。比如我只想保留这些截断的日志一个月时间,我希望作业自动维护。不需要我去手工作。有这样一个脚本cls_oracle.sh可以完全做到这个,当然它还会归档、清理其它日志文件,例如告警文件(alert_sid.log)等等。功能非常强大。
#!/bin/bash
## Script used to cleanup any Oracle environment.
## Cleans: audit_log_dest
# core_dump_dest
# user_dump_dest
## Rotates: Alert Logs
# Listener Logs
## Scheng: 00 00 /home/oracle/_cron/cls_oracle/cls_oracle.sh -d 31 > /home/oracle/_cron/cls_oracle/cls_oracle.log 2>
&1
## Created By: Tommy Wang 2012-09-10
## History:
#RM="rm -f"
RMDIR="rm -rf"
LS="ls -l"
MV="mv"
TOUCH="touch"
TESTTOUCH="echo touch"
TESTMV="echo mv"
TESTRM=$LS
TESTRMDIR=$LS
SUCCESS=0
FAILURE=1
TEST=0
HOSTNAME=`hostname`
ORAENV="oraenv"
TODAY=`date +%Y%m%d`
ORIGPATH=/usr/local/bin:$PATH
ORIGLD=$LD_LIBRARY_PATH
export PATH=$ORIGPATH
f_usage(){
echo "Usage: `basename $0` -d DAYS [-a DAYS] [-b DAYS] [-c DAYS] [-n DAYS] [-r DAYS] [-u DAYS] [-t] [-h]"
echo " -d = Mandatory default number of days to keep log files that are not explicitly passed as parameters."
echo " -a = Optional number of days to keep audit logs."
echo " -b = Optional number of days to keep background dumps."
echo " -c = Optional number of days to keep core dumps."
echo " -n = Optional number of days to keep network log files."
echo " -r = Optional number of days to keep clusterware log files."
echo " -h = Optional mode."
echo " -t = Optional test mode. Does not delete any files."
}if [ $# -lt 1 ]; then
f_usage
exit $FAILURE
fi
# Function used to check the validity of days.
f_checkdays(){
if [ $1 -lt 1 ]; then
exit $FAILURE
fi
if [ $? -ne 0 ]; then
exit $FAILURE
fi
}# Function used to cut log files.
f_cutlog(){
# Set name of log file.
LOG_FILE=$1
CUT_FILE=${LOG_FILE}.${TODAY}
FILESIZE=`ls -l $LOG_FILE | awk '{print $5}'`
# Cut the log file if it has not been cut today.
if [ -f $CUT_FILE ]; then
echo "Log Already Cut Today: $CUT_FILE"
elif [ ! -f $LOG_FILE ]; then
echo "Log File Does Not Exist: $LOG_FILE"
elif [ $FILESIZE -eq 0 ]; then
echo "Log File Has Zero Size: $LOG_FILE"
else
# Cut file.
echo "Cutting Log File: $LOG_FILE"
$MV $LOG_FILE $CUT_FILE
$TOUCH $LOG_FILE
fi
}# Function used to delete log files.
f_deleog(){
# Set name of log file.
CLEAN_LOG=$1
# Set time limit and confirm it is valid.
CLEAN_DAYS=$2
f_checkdays $CLEAN_DAYS
# Delete old log files if they exist.
find $CLEAN_LOG.[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] -type f -mtime +$CLEAN_DAYS -exec $RM {} ; 2>/dev/null
}# Function used to get database parameter values.
f_getparameter(){
if [ -z "$1" ]; then
return
fi
sqlplus -s /nolog < set head off pagesize 0 feedback off linesize 200 whenr sqlerror exit 1 conn / as sysdba select 'a='||value from v$parameter where name = '$PARAMETER'; EOF }# Function to get unique list of directories. f_getuniq(){ if [ -z "$1" ]; then return fi ARRCNT=0 MATCH=N x=0 for e in `echo $1`; do if [ ${#ARRAY[]} -gt 0 ]; then # See if the array element is a duplicate. while [ $x -lt ${#ARRAY[]} ]; do if [ "$e" = "${ARRAY[$x]}" ]; then MATCH=Y fi done fi if [ "$MATCH" = "N" ]; then ARRAY[$ARRCNT]=$e ARRCNT=`expr $ARRCNT+1` fi x=`expr $x + 1` done echo ${ARRAY[]} }# Parse the command line options. case $OPT in a) ADAYS=$OPTARG ;; b) BDAYS=$OPTARG ;; c) CDAYS=$OPTARG ;; d) DDAYS=$OPTARG ;; n) NDAYS=$OPTARG ;; r) RDAYS=$OPTARG ;; u) UDAYS=$OPTARG ;; t) TEST=1 ;; 当然要对日志文件(listener.log)进行定期清理,如果不定期清理,会遇到下面一些麻烦: 1:日志文件(listener.log)变得越来越大,占用额外的存储空间。(当然现在存储白菜价,不那几G的空间。但是我们还是要本着工匠情怀,精益求精) 2:日志文件(listener.log)变得太大会带来一些问题:LISTENER.LOG日志大小不能超过2GB,超过会导致LISTENER无法处理新的连接。 3:日志文件(listener.log)变得太大,给写入、查看带来的一些性能问题、麻烦。 也有人说是服务进程一般使用标准C函数Write写出到Listener.log,listener.log文件时使用的是O_WRONLY|O_CREAT|O_APPEND,O_APPEND即追加到文件的尾端,一般来说追加写方式不会因为文件越大写地越慢。撇开这个不谈,在一个很大的日志文件(listener.log)查找某一天或某一个错误,这个确实会带来一些性能问题。查找起来也相当麻烦。 所以应该定期对日志文件(listener.log)进行清理,另外一种说法叫截断日志文件。关于截断日志,要注意一些问题。初学ORACLE的时候遇到一个错误的截断日志的,下面演示一下 [oracle@DB- log]$ mv listener.log listener.log.20150114 [oracle@DB- log]$ cp /dev/null listener.log [oracle@DB- log]$ more listener.log 如上所示,这样截断日志(listener.log)后,服务进程(tnslsnr)并不会将新的信息写入listener.log,而是继续写入listener.log.20150114 [oracle@DB- log]$ tail listener.log.20150114 15-JAN-2015 22:47:59 serv_update EPPS 0 15-JAN-2015 22:58:00 serv_update EPPS 0 15-JAN-2015 23:08:00 serv_update EPPS 0 15-JAN-2015 23:18:01 serv_update EPPS 0 15-JAN-2015 23:38:02 serv_update EPPS 0 15-JAN-2015 23:41:02 serv_update EPPS 0 15-JAN-2015 23:50:26 ping 0 [oracle@DB- log]$ tail listener.log.20150114 15-JAN-2015 23:18:01 serv_update EPPS 0 15-JAN-2015 23:38:02 serv_update EPPS 0 15-JAN-2015 23:41:02 serv_update EPPS 0 15-JAN-2015 23:50:26 ping 0 15-JAN-2015 23:57:40 ping 0 15-JAN-2015 23echo " -u = Optional number of days to keep user dumps.":57:41 ping 0 15-JAN-2015 23:57:42 ping 0 15-JAN-2015 23:57:43 ping 0 [oracle@DB- log]$ more listener.log [oracle@DB- log]$ 规范正确的流程应该这么处理: Step 1:首先停止服务进程(tnslsnr)记录日志。 [oracle@DB- log]$ lsnrctl set log_status off; LSNRCTL for Linux: Version 10.2.0.4.0 - Production on 16-JAN-2015 00:02:59 Copyright (c) 19, 2007, Oracle. All rights reserved. Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.9.15)(PORT=1521))) LISTENER parameter "log_status" set to OFF The command completed successfully Step 2:将日志文件(listener.log)一份,以listener.log.yyyymmdd格式命名 [oracle@DB- log]$ cp listener.log listener.log.20150114 Step 3:将日志文件(listener.log)清空。清空文件的方法有很多 3.1 echo “” > filename 3.2 cp /dev/null 或 echo /dev/null > filename Step 4:开启服务进程(tnslsnr)记录日志 [oracle@DB- log]$ lsnrctl set log_status on; 当然也可以移走日志文件(listener.log),数据库实例会自动创建一个listener.log文件。 % lsnrctl set log_status off % mv listener.log listener.yyyymmdd % lsnrctl s15-JAN-2015 22:40:01 serv_update EPPS 0et log_status on 当然这些作应该通过shell脚本来处理,然后结合crontab作业定期清理、截断日志文件。例如网上的一个清理、截断日志文件的shell脚本。 rq=` date +"%d" ` cp $ORACLE_HOME/network/log/listener.log $ORACLE_BACKUP/network/log/listener_$rq.log cp /dev/null $ORACLE_HOME/network/log/listener.log su - oracle -c "lsnrctl set log_status on" 这样的脚本还没有解决一个问题,就是截断的日志文件保留多久的问题。比如我只想保留这些截断的日志一个月时间,我希望作业自动维护。不需要我去手工作。有这样一个脚本cls_oracle.sh可以完全做到这个,当然它还会归档、清理其它日志文件,例如告警文件(alert_sid.log)等等。功能非常强大。 #!/bin/bash ## Script used to cleanup any Oracle environment. ## Cleans: audit_log_dest # core_dump_dest # user_dump_dest ## Rotates: Alert Logs # Listener Logs ## Scheng: 00 00 /home/oracle/_cron/cls_oracle/cls_oracle.sh -d 31 > /home/oracle/_cron/cls_oracle/cls_oracle.log 2> &1 ## Created By: Tommy Wang 2012-09-10 ## History: #RM="rm -f" RMDIR="rm -rf" LS="ls -l" MV="mv" TOUCH="touch" TESTTOUCH="echo touch" TESTMV="echo mv" TESTRM=$LS TESTRMDIR=$LS SUCCESS=0 FAILURE=1 TEST=0 HOSTNAME=`hostname` ORAENV="oraenv" TODAY=`date +%Y%m%d` ORIGPATH=/usr/local/bin:$PATH ORIGLD=$LD_LIBRARY_PATH export PATH=$ORIGPATH f_usage(){ echo "Usage: `basename $0` -d DAYS [-a DAYS] [-b DAYS] [-c DAYS] [-n DAYS] [-r DAYS] [-u DAYS] [-t] [-h]" echo " -d = Mandatory default number of days to keep log files that are not explicitly passed as parameters." echo " -a = Optional number of days to keep audit logs." echo " -b = Optional number of days to keep background dumps." echo " -c = Optional number of days to keep core dumps." echo " -n = Optional number of days to keep network log files." echo " -r = Optional number of days to keep clusterware log files." echo " -h = Optional mode." echo " -t = Optional test mode. Does not delete any files." }if [ $# -lt 1 ]; then f_usage exit $FAILURE fi # Function used to check the validity of days. f_checkdays(){ if [ $1 -lt 1 ]; then exit $FAILURE fi if [ $? -ne 0 ]; then exit $FAILURE fi }# Function used to cut log files. f_cutlog(){ # Set name of log file. LOG_FILE=$1 CUT_FILE=${LOG_FILE}.${TODAY} FILESIZE=`ls -l $LOG_FILE | awk '{print $5}'` # Cut the log file if it has not been cut today. if [ -f $CUT_FILE ]; then echo "Log Already Cut Today: $CUT_FILE" elif [ ! -f $LOG_FILE ]; then echo "Log File Does Not Exist: $LOG_FILE" elif [ $FILESIZE -eq 0 ]; then echo "Log File Has Zero Size: $LOG_FILE" else # Cut file. echo "Cutting Log File: $LOG_FILE" $MV $LOG_FILE $CUT_FILE $TOUCH $LOG_FILE fi }# Function used to delete log files. f_deleog(){ # Set name of log file. CLEAN_LOG=$1 # Set time limit and confirm it is valid. CLEAN_DAYS=$2 f_checkdays $CLEAN_DAYS # Delete old log files if they exist. find $CLEAN_LOG.[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] -type f -mtime +$CLEAN_DAYS -exec $RM {} ; 2>/dev/null }# Function used to get database parameter values. f_getparameter(){ if [ -z "$1" ]; then return fi sqlplus -s /nolog < set head off pagesize 0 feedback off linesize 200 whenr sqlerror exit 1 conn / as sysdba select 'a='||value from v$parameter where name = '$PARAMETER'; EOF }# Function to get unique list of directories. f_getuniq(){ if [ -z "$1" ]; then return fi ARRCNT=0 MATCH=N x=0 for e in `echo $1`; do if [ ${#ARRAY[]} -gt 0 ]; then # See if the array element is a duplicate. while [ $x -lt ${#ARRAY[]} ]; do if [ "$e" = "${ARRAY[$x]}" ]; then MATCH=Y fi dodef test_login(self):ne fi if [ "$MATCH" = "N" ]; then ARRAY[$ARRCNT]=$e ARRCNT=`expr $ARRCNT+1` fi x=`expr $x + 1` done echo ${ARRAY[]} }# Parse the command line options. case $OPT in a) ADAYS=$OPTARG ;; b) BDAYS=$OPTARG ;; c) CDAYS=$OPTARG ;; d) DDAYS=$OPTARG ;; n) NDAYS=$OPTARG ;; r) RDAYS=$OPTARG ;; u) UDAYS=$OPTARG ;; t) TEST=1 ;; 你可以将BAT脚本转换成Shell脚本(.sh)如下所示: ```bash #!/bin/bash echo "程序正在启动中.." CLSNAME="macs_tool20.mytools.macs.ui.basedata.MaiPARAMETER=$1n" CLSPATH="" for jarfile in lib.jar do CLSPATH="$CL测试接口SPATH:$jarfile" done ja -Xms128M -Xmx512M -cp .:$CLSPATH $CLSNAME ``` 这个Shell脚本将完成与原始BAT脚本相同的任务,包括设置`CLSNAME`和`CLSPATH`,然后运行Ja应用程序。不过请注意,Shell脚本中使用`:`而不是`;`来分隔类路径,并且`$`符号用于引用变量。此外,我们添加了一个Shebang(`#!/bin/bash`)以指示这是一个Bash脚本。oracle11g rac diag/tnslsnr/pgis2/listener/alert 中的文件能删除吗
求大神帮忙把bat脚本改写成sh脚本
su - oracle -c "lsnrctl set log_status off"
版权声明:本文内容由互联。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发 836084111@qq.com 邮箱删除。