zoukankan      html  css  js  c++  java
  • 文件读写监控(inotify, systemtap)

    一、inotify
         inotify是内核的一个特性,可以用来监控目录、文件的读写等事件,当监控目标是目录时,inotify除了会监控目录本身,还会监控目录中的文件。inotify的监控功能由如下的几个系统调用完成:inotify_init(2) (or inotify_init1(2)), inotify_add_watch(2), inotify_rm_watch(2), read(2), and close(2).
         inotify的主要操作基于inotify_init 返回的inotify文件描述符,该描述符的作用类似于epoll用到的epoll_fd。inotify在监控目录的时候,不支持对目录的递归监控,即只能监控一层目录,如果需要递归监控的,就需要将这些目录通过inotify_add_watch添加进来。
         inotify目前只能检测到目标文件(夹)发生了什么操作,无法检查出是哪个进程触发的这项操作。(注:fanotify函数接口支持获取触发操作的进程pid,但是fanotify支持的检测类型比inotify少太多,使用者也比较少)
         
         需求:监控/home/sxhlinux/test/test.txt的状态
         
      C语言实现:
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/inotify.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/epoll.h>
     
    int main(void)
    {
        char *filename = "./log.txt";
     
        int inoti_fd = inotify_init1(IN_CLOEXEC);
        if (inoti_fd == -1) {
            printf("inotify_init failed, %s
    ", strerror(errno));
            exit(-1);
        }
     
        int file_fd = inotify_add_watch(inoti_fd, filename, IN_ALL_EVENTS);
        if (file_fd == -1) {
            printf("inotify_add_watch failed, %s
    ", strerror(errno));
            exit(-1);
        }
     
        int epoll_fd = epoll_create(5);
        if (epoll_fd == -1) {
            printf("epoll_create failed, %s
    ", strerror(errno));
            goto end;
        }
     
        struct epoll_event ev, event[5];
     
        memset(&ev, 0, sizeof(ev));
        ev.events = EPOLLIN | EPOLLET;
        ev.data.fd = inoti_fd;
        if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, inoti_fd, &ev) == -1) {
            printf("epoll_ctl failed, %s
    ", strerror(errno));
            goto end;
        }
     
        int buf_size = sizeof(struct inotify_event) + 64 * sizeof(char);
        struct inotify_event * instance = malloc(buf_size);
        memset(instance, 0, buf_size);
     
        int value = 0;
        while ((value = epoll_wait(epoll_fd, event, 5, -1)) != -1) {
            int i = 0;
            for (i = 0; i < value; i ++) {
                if (event[i].data.fd == inoti_fd) {
                    if (read(inoti_fd, instance, buf_size) > 0)
                        printf("file_id is %d, event is %u, cookie is %u, name is %s
    ",
                                instance->wd, instance->mask, instance->cookie, instance->name);
                    else
                        printf("read inoti_fd failed, %s
    ", strerror(errno));
                }
                else
                    printf("unknown file_fd %d
    ", event[i].data.fd);
            }
        }
     
    end:
        inotify_rm_watch(inoti_fd, file_fd);
     
        return 0;
    
         Python实现:
    #!/usr/bin/python
     
    import logging
    from inotify import adapters
     
    _DEFAULT_LOG_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
     
    _LOGGER = logging.getLogger(__name__)
     
    def _configure_logging():
        _LOGGER.setLevel(logging.DEBUG)
        ch = logging.FileHandler('./record', 'a')
        formatter = logging.Formatter(_DEFAULT_LOG_FORMAT)
        ch.setFormatter(formatter)
        _LOGGER.addHandler(ch)
     
    def _main():
        i = adapters.Inotify()
        i.add_watch('/var/lib/logrotate.status')
     
        for event in i.event_gen():
            if event:
                (header, type_names, watch_path, filename) = event
                print ("WD=(%d) MASK=(%d) COOKIE=(%d) LEN=(%d) MASK->NAMES=%s WATCH-PATH=[%s] FILENAME=[%s]",
                header.wd, header.mask, header.cookie, header.len, type_names, watch_path.decode('utf-8'), filename.decode('utf-8'))
                _LOGGER.info("WD=(%d) MASK=(%d) COOKIE=(%d) LEN=(%d) MASK->NAMES=%s WATCH-PATH=[%s] FILENAME=[%s]",
                header.wd, header.mask, header.cookie, header.len, type_names, watch_path.decode('utf-8'), filename.decode('utf-8'))
     
    if __name__ == '__main__':
        _configure_logging()
        _main()
    
         shell命令(依赖inotify-tools软件包):
    #监控log.txt发生的操作,并输出到record文件中,另外inotifywait命令的-r选项支持递归遍历
    $ inotifywait -m log.txt -o record
     
    #inotifywatch 命令则用于统计一段时间内,某个文件所发生操作的统计数据
    #上述的两个命令的具体用法参照man手册
    

     

    二、systemtap监控
         systemtap可以监控系统调用,我们使用stap带的一个监控inode的插件inodewatch.stp 来实现对文件的监控。
    $ yum install systemtab -y
    $ yum install kernel-debug-debuginfo     #stap监控系统调用需要
    $ stap -ve 'probe begin { log("hello world") exit() }'     #测试stap是否安装成功
    $ ls -i log.txt      #查看要监控文件的inode号 2360637
    $ df -h      #查看log.txt所在的磁盘分区
    $ cat /proc/partitions     #查看各个磁盘分区的major、minor号 8 2
    $ stap /usr/share/doc/systemtap-1.6/examples/io/inodewatch.stp 0x8 0x2 2360637     #监控log.txt即(0x8 0x2 2360637)所进行的操作,同时会显示出执行操作的进程ID
    

      

  • 相关阅读:
    C# Asp.NET实现上传大文件(断点续传)
    asp.net mvc大文件上传、断点续传功能。
    JS&ASPDotNet_大文件上传问题
    javascript之大文件分段上传、断点续传(一)
    使用JS实现可断点续传的文件上传方案
    js+php大文件分片上传
    文件/大文件上传功能实现(JS+PHP)全过程
    js实现大文件分片上传的方法
    [每天一个Linux小技巧] 查看时钟源精度
    Linux
  • 原文地址:https://www.cnblogs.com/sxhlinux/p/6420932.html
Copyright © 2011-2022 走看看