统计用户在线时长

1. 获取用户登入与登出系统信息

/var/log/文件下有3个日志文件,记录了与用户登录有关的信息。

  • /var/run/utmp: It contains information about the users who are currently logged onto the system. Who command is used to fetch the information from the file.
  • /var/log/wtmp: It contains historical utmp. It keeps the users login and logout history. The last command uses this file to display the information.
  • /var/log/btmp: It contains bad login attempts.

wtmpbtmp是可执行文件,使用命令lastlastb可以取取。

root@jmu-cs:/var/log# file -i wtmp
wtmp: application/x-dbt; charset=binary

root@jmu-cs:/var/log# file -i btmp
btmp: application/octet-stream; charset=binary

(1)utmp

utmp记录了当前谁在使用系统,使用命令who可以读取utmp文件中的内容,举例:

# who
qiankun  tty1         2022-04-21 00:17
root     tty2         2022-04-21 00:23
root     pts/0        2022-05-19 17:55 (172.20.11.16)

(2)wtmp

wtmp记录了用户登入与登出的历史信息。使用命令last可以读取wtmp文件中的内容,举例:

last wtmp -Fw > last.dat

last -f wtmp -Fw > last.dat

其中,

  • -f--file),指定wtmp文件,若无指定,默认为/var/log/wtmp
  • -F--fulltimes),显示完整的登入与登出的日期与时间。没加-F显示Mon May 16 15:19 - 15:55,加了-F显示Mon May 16 15:19:21 2022 - Mon May 16 15:55:26 2022
  • -w--fullnames),显示完整用户名和域名

![Tip]

上完实验课应及时读取用户登入也登出信息(或者将/var/log/wtmp备份),否则随着系统运行,会覆盖之前的记录。

(3)btmp

btmp记录了用户登录失败的信息,使用命令lastb可以读取btmp文件中的内容,举例:

# lastb -Fw
u20202121007 ssh:notty    172.21.4.49      Sat Jun  4 00:50:28 2022 - Sat Jun  4 00:50:28 2022  (00:00)
u20202121007 ssh:notty    172.21.4.49      Sat Jun  4 00:50:12 2022 - Sat Jun  4 00:50:12 2022  (00:00)
u20202121007 ssh:notty    172.21.4.49      Sat Jun  4 00:50:05 2022 - Sat Jun  4 00:50:05 2022  (00:00)

btmp begins Sat Jun  4 00:50:05 2022

2. 统计用户在线时长

除了统计用户在线时长,也统计用户自动登录次数,用于识别使用客户端设置自动登录的行为,核心代码如下:`

def get_username_duration_times(filename, start_dt, end_dt, d_user_name_info):
    d_username_duration_times = AutoVivification()

    # calculate the overlapping intervals
    d_username_lists_overlapping = dict.fromkeys(d_user_name_info) # username : a list of [overlapping_start, overlapping_end]

    with open(filename, 'r') as f:
        for line in f.readlines()[-3::-1]: # skip the last two line, iterate in reverse order
        #for line in f:
            # stats ends util the empty line
            '''
            if not line.strip():
                break
            '''

            l = line.split()

            username = l[0]
            if username not in d_user_name_info:
                continue

            # get the start time of period
            str_dt = ' '.join(l[3:8]) # Tue Mar 16 11:44:57 2021
            period_start = parse(str_dt)

            # get the end time of period
            if 'still logged in' in line:
                period_end = end_dt
            elif 'down' in line:
                # root     pts/1        36.249.132.196   Sun Mar  7 21:59:04 2021 - down                      (00:06)
                duration = l[-1] # (00:06)
                period_end = period_start +  datetime.timedelta(hours=float(duration[1:3]), minutes=float(duration[4:6]))
            else:
                str_dt = ' '.join(l[9:14]) # Tue Mar 16 11:44:57 2021
                period_end = parse(str_dt)

            # not in the specified range
            if period_end<=start_dt or period_start>=end_dt:
                continue

            # get the real interval with specified time range
            if period_start < start_dt:
                period_start = start_dt
            if period_end > end_dt:
                period_end = end_dt

            # get the overlapping duration considering mupltiple login
            if not d_username_lists_overlapping[username]: # init a loop
                d_username_lists_overlapping[username] = [[period_start, period_end]]
            else:
                old_overlapping = d_username_lists_overlapping[username][-1]
                if old_overlapping[1] < period_start:
                    d_username_lists_overlapping[username].append([period_start, period_end])
                else:
                    d_username_lists_overlapping[username][-1] = [old_overlapping[0],
                                       max(old_overlapping[1], period_end) ]


            # detect autologin,  stats
            td = period_end - period_start
            duration = td.total_seconds()
            if (username in d_username_duration_times) and (duration in d_username_duration_times[username]):
                d_username_duration_times[username][duration] += 1
            else:
                d_username_duration_times[username][duration] = 1

        return d_username_lists_overlapping, d_username_duration_times

完整的代码见accumulate_overlapping_duration_detect_autologin.py

本文系Spark & Shine原创,转载需注明出处本文最近一次修改时间 2022-06-05 10:56

results matching ""

    No results matching ""