#!/usr/bin/env python3 ################################################################################ # # Copyright (c) 2020, Perforce Software, Inc. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # = Date # # $Date: 2020/09/18 $ # # = Description # # Collect information about workspaces and output them in csv format: # name,owner,last_update_date,last_access_date,nb_synced_files # # = Usage # # clientStats.py a_checkpoint|a_checkpoint.gz > clientStats.out # Example of queries: # - list of clients sorted on last access date: # sort -t"," -k 3 clientStats.out # - list of clients sorted in reverse order on number of synced files: # sort -t"," -k 5 -n -r clientStats.out # ################################################################################ from __future__ import print_function import re import time import sys import gzip import mimetypes import os import math def cmdUsage(): sys.exit("Usage: clientStats.py a_checkpoint|a_checkpoint.gz") def main(): if len(sys.argv) < 2: cmdUsage() clients = {} filename = sys.argv[1] if mimetypes.guess_type(filename)[1] == 'gzip': ckp = gzip.open(filename, "rb") else: ckp = open(filename, "rb") clientSpecRE = re.compile(b'@pv@ [0-9]* @db.domain@ @(.*?)@ 99 @.*?@ @.*?@ @.*?@ @.*?@ @(.*?)@ ([0-9]*) ([0-9]*) [0-9]* @.*') haveRE = re.compile(b'@pv@ [0-9]* @db.have@ @//(.*?)/.*') stopRE = re.compile(b'.* @db.label@ .*') print("Processing, it may take several hours...\n", end='', file=sys.stderr) sys.stderr.flush() for line in ckp: match = clientSpecRE.search(line) if match: client = match.group(1) if client not in clients: clients[client] = {} clients[client]["have"] = 0 clients[client]["owner"] = match.group(2) clients[client]["update"] = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(float(match.group(3)))) clients[client]["access"] = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(float(match.group(4)))) else: match = haveRE.search(line) if match: client = match.group(1) if client not in clients: clients[client] = {} clients[client]["have"] = 0 clients[client]["owner"] = b"unknown" clients[client]["update"] = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(0.0)) clients[client]["access"] = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(0.0)) clients[client]["have"] += 1 else: if stopRE.search(line): # stop, no need to look further break ckp.close() # In order to output bytes to stdout, sys.stdout.buffer must be used in Python 3 # but this is not compatible with Python 2, so to make it compatible: output = getattr(sys.stdout, 'buffer', sys.stdout) for (key, value) in clients.items(): output.write(key + b"," + value["owner"] + b",") sys.stdout.write(value["update"] + "," + value["access"] + "," + str(value["have"]) + "\n") sys.stdout.flush() if __name__ == '__main__': main()