基于inotify的告警脚本

自动告警脚本 最近项目上有这样一个需求:系统中有一个后台服务会不断的生成监控日志,根据系统的运行情况,它每天会在目录/var/alarms下生成一个文件,文件名带有时间戳,其中内容格式如下: $ cat /var/alarms/alarms-20150228130522.csv node,summary,occurrence,proiority VIQ002,heartbeat failure,2/12/2015 01:23 AM,critical VIQ002,packages are rejected,2/12/2015 01:22 AM,major VIQ002,connection cannot be established,2/11/2015 01:23 AM,medium VIQ001,packages are rejected,2/11/2015 01:23 AM,warning VIQ001,connection cannot be established,2/09/2015 01:23 AM,medium ... 运维团队需要监控这个目录,如果里边的文件发生了变化,就要及时的发送邮件给工程团队解决。我们当然不可能人工的监控该目录,然后编写邮件,再拷贝粘贴,所以需要编写一个脚本来自动化这个任务。 处理方法有两种: 编写一个crontab的任务,每隔五分钟轮询一下,然后编写脚本来探测变化,发送邮件 使用操作系统提供的inotify相关API探测变化,编写脚本发送邮件 不过作为程序员,第二种方法显然更高级一些。另外相对于检测文件变化(对比目录树,检查时间戳,而且还要记录上一次变更的状态等),编写一个发送邮件的脚本要简单得多。 使用inotify 如果在Linux下,我们可以使用inotify相关的工具,你可以使用你正在使用的系统下的包管理工具来安装。也可以直接从源码包编译安装。 安装之后,系统中就有了一个叫做inotifywait的命令,这个命令提供多个参数。默认的inotifywait在接收到指定的事件(文件变化)后,会打印信息并退出。可以使用-m参数让inotifywati处于监听状态。-e参数指定需要监听的事件类型,下面是几个常见的事件类型: CREATE,创建 MODIFY,修改 CLOSE_WRITE,CLOSE,写入成功 还可以通过--format来指定事件的输出,%w表示监控的文件名,%f表示如果被监控的对象是目录,则当发生事件时返回文件名。比如下面的命令: $ inotifywait -m -e close_write /var/alarms --format "%w%f" 表示以监控模式(事件发生后不退出,继续监听),监听close_write事件,在/var/alarms目录上,并且输出的格式为%w%f。 这样我们在另一个窗口上模拟事件发生: $ touch /var/alarms/alarms-20150228130522.csv 当前的窗口就会出现/var/alarms/alarms-20150228130522.csv这样的输出。有了这个功能,我们只需要编写一段简单的脚本就可以完成上一小节中的问题了: #!/bin/bash DIR=$1 inotifywait -m -e close_write $DIR --format "%w%f" | while read FILE do cat ${FILE} | mail -s "Alarm: $FILE" juntao....

March 1, 2015 1 min

制作一个多彩的svn diff脚本

Code Review 在ThoughtWorks,我们几乎每天都会进行一个叫code review或者code diff的活动:每天下午5:00,团队成员围坐在一起,将今天的修改大概过一下,这样做的好处非常明显: 分享业务知识,了解彼此的工作 分享技术细节,比如有人使用了某种设计模式 帮助别人发现问题,比如逻辑错误等,群策群力 经过实践,code reivew可以快速发现问题,而且可以尽可能多的分享知识,是一种ThoughtWorker们喜闻乐见的学习/娱乐形式。 但是随着项目的不同,各个团队使用的版本管理工具都不一样。用惯了git的非常漂亮的diff子命令之后,svn的diff简直就是战五渣。没有高亮,没有进度条,就是黑底白字的一些文本,实在无法让人提起兴趣。 这篇文章分享一个简单的方法,可以让你很容易的把svn的diff打造成一个漂亮的工具: diff格式 Diff是一种通用的表示文本差异的格式,细节可以看我之前写过一篇关于diff和patch的文章。需要说明的是,它作为一种标准格式,很多编辑器都提供对这种格式的高亮显示,比如现在非常流行的Sublime Text编辑器: 默认的,svn的diff命令会生成这样朴素的输出: 命令行的diff高亮显示 在Mac下,可以通过brew来安装一个命令行工具,这个工具可以将Diff格式高亮显示: $ brew install colordiff 有了这个工具,就可以将svn生成的Diff格式高亮显示出来: $ svn diff | colordiff 但是你可能已经发现这些神奇的^M,这是Windows系统中的换行符在Unix类系统中的展示,我们需要将Diff先转换一次: $ svn diff | dos2unix | colordiff 如果你的系统中没有dos2unix,可以用brew来安装: $ brew install dos2unix unix2dos 分页器 *nix系统下有两种分页器:more和less,less比more的功能更丰富。less有很多的参数,我们这里选用了3个常见的: -s: 压缩连续的空白行为一行 -M: 给出更多的提示信息,包含行号,百分比等 +Gg: 先跳至要查看文件的末尾,再跳至文件开头,这样从less就可以得到整个流的长度,从而计算出正确的百分比。当然如果是单独文件时,less是明确知道文件长度的,但是如果是从流中重定向过来的文本,less无法在开始时就得知长度。 下面这条命令可以将当前目录下的所有html文件分屏显示,并且在每一屏的最后一行显示百分比等信息: $ cat *.html | less -s -M +Gg 放在一起 好了,我们将每个部分都已经讲解了一遍了,现在让我们将这些零件串起来,在svn的working copy中执行这条命令就可以得到非常漂亮的,分页显示的Diff: $ svn diff | dos2unix | colordiff | less -s -M +Gg 当然,还可以用一个alias(别名)来节省敲入的字符数:...

February 18, 2015 1 min

Linux命令行中的7个小技巧

Linux命令行中的7个小技巧 命令行是开发者的好朋友,*nix系统(包括Mac OS X和各种Linux)都自带了强大的Shell环境,作为一个专业的程序员,Shell是离不开的。这里总结了几个常用的小技巧,都是我自己平时经常用,而又不想每次都去Google的。 如何知道哪个进程在监听4000端口? 当启动服务时,经常会遇到想要Address already in use这样的异常,那么如何知道是哪个进程占用了该端口呢? $ lsof -i :4000 lsof会列出系统目前打开的文件(List open files,Linux世界中,一切都是文件),-i表示网络地址(Internet address),注意此处的冒号。如果不带参数,lsof会列出所有打开的网络地址: $ lsof -i :4000 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME ruby 32303 jtqiu 7u IPv4 0x947b402a4bb8370b 0t0 TCP *:terabase (LISTEN) Shell中如何设置代理? 很多公司都会有一个代理服务器供员工上外网使用,命令行中设置代理非常容易: export http_proxy="http://username:password@hosename:port" 如果密码中有特设字符,比如$的话,需要转义一下。使用URLEncoding即可,比如$就是%24。最简单的就是在Chrome的Console中输入encodeURIComponent("$")来获得转义字符。 如果不想对某些地址使用代理,可以设置no_proxy环境变量: export no_proxy="127.0.0.1, localhost, *.cnn.com, 192.168.1.10, domain.com:8080" 如何为svn中的脚本设置可执行属性 你在Linux下创建了一个可执行脚本e2e_test.sh,但是团队里的其他人工作在Windows系统上,当你提交可执行脚本之后,他们checkout的是一个不能执行的文件!(其实也在情理之中,Windows这种垃圾货什么时候正常过呢?) 这时候可以通过给这个脚本设置一个svn的属性: svn propset svn:executable "*" e2e_test.sh 这样在Windows上才heckout之后就正常了。 在Bash脚本中如何判断一个文件是否可执行? 有时候我们在Bash中需要判断某个文件是否可以执行,这行脚本可以解救你: if [ -x $FILENAME ]; then # the file is executable fi 判断某个文件是否存在的脚本为:...

February 14, 2015 2 min

svn中的分支管理

分支策略 本来准备整理一篇版本管理中,关于分支的维护策略。后来看到阮一峰老师的这篇文章,觉得非常清晰,这里给出一个链接供参考。 另外一个有意思的链接在这里,也可以一并参看。 本文就仅仅简单的描述一下,使用svn的命令行工具,如何具体完成合并的操作: 在Svn中合并分支 在svn中,要合并两个分支(通常是将某个分支b合并到trunk上,不过另一种模式下也可以将trunk合并到b上)非常简单,我们以一个简单的例子来说明其步骤。 比如我们要将trunk上的修改合并到分支b上,操作可以分为4步: 切换到分支b上(之前执行过svn co /path/branches/b之后的目录) 使用svn log --stop-on-copy命令得到该分支的最早版本号 使用svn merge --dry-run -rXXX:HEAD /path/trunk来预览合并列表 合并 在第二步中,一个典型的输出是这样的: $ svn log --stop-on-copy ... r231625 | juntao | 2014-07-10 13:33:36 +1000 (Thu, 10 Jul 2014) | 1 line Juntao Change the version in pom.xml ------------------------------------------------------------------------ r231623 | abruzzi | 2014-07-10 13:22:00 +1000 (Thu, 10 Jul 2014) | 1 line Spike on data structure of c-wifi, a workable prototype ------------------------------------------------------------------------ r231610 | juntao | 2014-07-10 12:29:01 +1000 (Thu, 10 Jul 2014) | 1 line Create a new branch for c-wifi ------------------------------------------------------------------------ 一旦有了这个修订号(231610),就可以开始合并了:...

August 25, 2014 1 min

ssh forward 101

Generate the public and private key pair This step is quite strightforward, just generate the keys by using ssh-keygen: $ ssh-keygen #specify the key file name (I use the id_ plus remote site hostname) then you’ll get 2 keys locally, you can do this step in any place, but people do it on their home-dir/.ssh, after the creation, you need to change the mask of the key file: $ chmod 600 id_site...

October 25, 2012 2 min