From 778c3bcd38ee345d4ef1c0e9be1db9480c8d699e Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sun, 1 Nov 2020 09:03:06 +0100 Subject: [PATCH 01/37] Create codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 68 +++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000..298e95e8 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,68 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# ******** NOTE ******** + +name: "CodeQL" + +on: + push: + branches: [ dev ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ dev ] + schedule: + - cron: '16 07 * * 0' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + language: [ 'python' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more... + # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 From 6587921eaccdf74cb1f38a8ddecfcc5ef46055c6 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Mon, 2 Nov 2020 21:14:05 +0100 Subject: [PATCH 02/37] Replace searching $PATH with os.popen --- src/tuptime | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/tuptime b/src/tuptime index 92c0a6a2..e5fd27a3 100644 --- a/src/tuptime +++ b/src/tuptime @@ -257,18 +257,11 @@ def get_os_values(): logging.info('System = BSD') - def _sysctl(): - """Set sysctl execution path""" - for path in os.environ["PATH"].split(os.pathsep): - sysctl_path = os.path.join(path, 'sysctl') - if os.path.isfile(sysctl_path) and os.access(sysctl_path, os.X_OK): - return sysctl_path - try: sis['btime'] = time.clock_gettime(time.CLOCK_REALTIME) - time.clock_gettime(time.CLOCK_MONOTONIC) except Exception as exp: logging.info('Old btime assignment. %s', str(exp)) - sysctl_out = os.popen(_sysctl() + ' -n kern.boottime').read() + sysctl_out = os.popen('sysctl -n kern.boottime').read() # Some BSDs report the value assigned to 'sec', others do it directly if 'sec' in sysctl_out: # FreeBSD, Darwin sis['btime'] = sysctl_out.split(' sec = ')[1].split(',')[0] @@ -296,7 +289,7 @@ def get_os_values(): sis['rntime'] = sis['uptime'] try: - sysctl_out = os.popen(_sysctl() + ' -xn kern.boot_id 2>&1').read() + sysctl_out = os.popen('sysctl -xn kern.boot_id 2>&1').read() if 'Dump' in sysctl_out: sis['bootid'] = sysctl_out.split('Dump:')[-1].rstrip() else: From 7282030bb9783827ec761a9da8fe1aa67ac5b748 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Mon, 2 Nov 2020 21:25:05 +0100 Subject: [PATCH 03/37] Refactoring test path with exist_ok=True --- src/tuptime | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tuptime b/src/tuptime index e5fd27a3..e0e87454 100644 --- a/src/tuptime +++ b/src/tuptime @@ -407,9 +407,8 @@ def gain_db(sis, arg): # Test path arg.db_file = os.path.abspath(arg.db_file) # Get absolute or relative path try: - if not os.path.isdir(os.path.dirname(arg.db_file)): + if os.makedirs(os.path.dirname(arg.db_file), exist_ok=True): logging.info('Making path = %s', str(os.path.dirname(arg.db_file))) - os.makedirs(os.path.dirname(arg.db_file)) except Exception as exp_path: logging.error('Checking DB path "%s": %s', str(os.path.dirname(arg.db_file)), str(exp_path)) sys.exit(-1) From 2bb066fc9ede772f7fa8970d95358e44fc5e2f79 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Mon, 2 Nov 2020 22:14:36 +0100 Subject: [PATCH 04/37] Argument option --decp with deprecated warning --- src/tuptime | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/tuptime b/src/tuptime index e0e87454..38258acb 100644 --- a/src/tuptime +++ b/src/tuptime @@ -79,6 +79,14 @@ def get_arguments(): type=int, help='number of decimals in percentages' ) + parser.add_argument( + '--decp', + dest='decp', + default=None, + action='store', + type=int, + help=argparse.SUPPRESS + ) parser.add_argument( '-f', '--filedb', dest='db_file', @@ -243,6 +251,10 @@ def get_arguments(): if arg.at is not None: arg.since = arg.until = arg.at + if arg.decp: + arg.dec = arg.decp + logging.warning('Argument \'--decp\' is deprecated in favour of \'-e\' or \'--dec\'.' ) + logging.info('Arguments = %s', str(vars(arg))) return arg From 4af43c059e45256e06f5027de9da09348964063b Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Tue, 3 Nov 2020 20:13:15 +0100 Subject: [PATCH 05/37] Playing with subprocess. Commented lines --- src/tuptime | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tuptime b/src/tuptime index 38258acb..724a1256 100644 --- a/src/tuptime +++ b/src/tuptime @@ -274,6 +274,8 @@ def get_os_values(): except Exception as exp: logging.info('Old btime assignment. %s', str(exp)) sysctl_out = os.popen('sysctl -n kern.boottime').read() + # # import subprocess + # # sysctl_out = subprocess.check_output(['sysctl', '-n', 'kern.boottime'], timeout=1, text=True) # Some BSDs report the value assigned to 'sec', others do it directly if 'sec' in sysctl_out: # FreeBSD, Darwin sis['btime'] = sysctl_out.split(' sec = ')[1].split(',')[0] @@ -301,6 +303,8 @@ def get_os_values(): sis['rntime'] = sis['uptime'] try: + # # import subprocess + # # sysctl_out = subprocess.check_output(['sysctl', '-xn', 'kern.boot_id'], timeout=1, text=True) sysctl_out = os.popen('sysctl -xn kern.boot_id 2>&1').read() if 'Dump' in sysctl_out: sis['bootid'] = sysctl_out.split('Dump:')[-1].rstrip() From 8324dc1927462a0fedd9138f5c1a2156af732f0f Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Thu, 5 Nov 2020 22:13:35 +0100 Subject: [PATCH 06/37] Update barchart with events counter option --- misc/scripts/README.txt | 5 +- misc/scripts/tuptime-barchart.py | 143 ++++++++++++++++++++----------- 2 files changed, 95 insertions(+), 53 deletions(-) diff --git a/misc/scripts/README.txt b/misc/scripts/README.txt index 62553d46..a25809f5 100644 --- a/misc/scripts/README.txt +++ b/misc/scripts/README.txt @@ -39,5 +39,6 @@ db-tuptime-migrate-4.0-to-5.0.sh ____Plots____ tuptime-barchart.py - Graph a plot with all hours per state inside each day from tuptime - csv output. Playground script. + Graph a plot with the number of hours (default) or events (-x swich) + per state along each day. It gets the info from tuptime csv output. + Playground script. diff --git a/misc/scripts/tuptime-barchart.py b/misc/scripts/tuptime-barchart.py index 97205e6b..ea2775f2 100644 --- a/misc/scripts/tuptime-barchart.py +++ b/misc/scripts/tuptime-barchart.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -"""Sample plot with hours per every state in each day -from the info that the tuptime command report""" +"""Sample plot that reports the number of hours/events per every state +in each day. It extracts the info from tuptime command execution""" from datetime import datetime, timedelta @@ -61,6 +61,13 @@ def get_arguments(): help='window width', type=int ) + parser.add_argument( + '-x', + dest='report_events', + action='store_true', + default=False, + help='swich to report startup/shutdown events instead of hours' + ) arg = parser.parse_args() return arg @@ -68,14 +75,14 @@ def get_arguments(): def date_check(arg): """Check and clean dates""" - # Set user or default end date. + # Set user provided or default end date if arg.edate: end_date = dateutil.parser.parse(arg.edate) else: end_date = datetime.today() print('Default end:\tnow') - # Set user or default begind date. Days ago... + # Set user provided or default begind date. Days ago... if arg.bdate: begin_date = dateutil.parser.parse(arg.bdate) else: @@ -104,14 +111,13 @@ def date_range(date_limits): dstart = dateutil.parser.parse(date_limits[0]) dend = dateutil.parser.parse(date_limits[1]) - # Split time range in days, list with every day + # Split time range in days while dstart <= dend: dlimit.append(dstart) dstart += timedelta(days=1) - # Finally add last day time range until midnight - dlimit.append(dend) + dlimit.append(dend) # Finally add last day time range until midnight - # Conver to epoch dates, pack two of them, begin and end for each split, and create a list with all + # Convert to epoch dates, pack two of them, begin and end for each split, and create a list with all for reg in range(1, len(dlimit)): ranepo.append([int(dlimit[reg-1].timestamp()), int(dlimit[reg].timestamp())]) xlegend.append(datetime.fromtimestamp(dlimit[reg-1].timestamp()).strftime('%Y-%m-%d')) @@ -128,9 +134,9 @@ def main(): date_limits = date_check(arg) date_list, xlegend = date_range(date_limits) - nran = 0 # Range number daysplt = [] # List for all day splits with their events ftmp = tempfile.NamedTemporaryFile().name # File to store Tuptime csv + bad = None # Iterate over each element in (since, until) list for nran, _ in enumerate(date_list): @@ -144,71 +150,86 @@ def main(): else: subprocess.call(["tuptime", "-lsc", "--tsince", tsince, "--tuntil", tuntil], stdout=out) - # Get csv file + # Parse csv file daysplit_events = [] with open(ftmp) as csv_file: csv_reader = csv.reader(csv_file, delimiter=',') - bad = None # Register bad shutdown for row in csv_reader: - l_row = [] # List for events in csv rows + l_row = [0, 0, 0] # Events in csv rows # Control how was the shutdown if (row[0] == 'Shutdown') and (row[1] == 'BAD'): bad = True - # Populate list with (uptime, downtime ok, downtime bad) - if (row[0] == 'Uptime') or (row[0] == 'Downtime'): + if arg.report_events: + # Populate list with (startup, shutdown ok, shutdown bad) + if ((row[0] == 'Startup') or (row[0] == 'Shutdown')) and len(row) > 2: + + if row[0] == 'Startup' and row[2] == 'at': + l_row[0] = 1 + + if row[0] == 'Shutdown' and row[2] == 'at': + if bad is True: + l_row[2] = 1 + else: + l_row[1] = 1 + bad = False - if row[0] == 'Uptime': - # Add 0 or value to first position - l_row.append(int(row[1])) - else: - l_row.append(0) + else: + # Populate list with (uptime, downtime ok, downtime bad) + if (row[0] == 'Uptime') or (row[0] == 'Downtime'): - if row[0] == 'Downtime': - # Add (0, value) or (value, 0) to the end - if bad is True: - l_row.extend((0, int(row[1]))) - else: - l_row.extend((int(row[1]), 0)) - bad = False # Reset false - else: - l_row.extend((0, 0)) + if row[0] == 'Uptime': + l_row[0] = int(row[1]) - # Add to events list per day - daysplit_events.append(l_row) + if row[0] == 'Downtime': + if bad is True: + l_row[2] = int(row[1]) + else: + l_row[1] = int(row[1]) + bad = False - print('Got range --->\t' + str(nran) + ' with ' + str(len(daysplit_events)) + ' events') + # Add to events list per day + daysplit_events.append(l_row) - # Per day, get total value for each type of event and convert seconds to hours - daysplit_events = [(sum(j) / 3600) for j in zip(*daysplit_events)] + print('Got range --->\t' + str(nran) + ' with ' + str(len([i for i in daysplit_events if i != [0, 0, 0]])) + ' events') + + # Per day, get total value for each type of event + if arg.report_events: + daysplit_events = [(sum(j)) for j in zip(*daysplit_events)] + else: + # Convert seconds to hours + daysplit_events = [(sum(j) / 3600) for j in zip(*daysplit_events)] # Populate daysplt list with totals daysplt.append(daysplit_events) print('Ranges got:\t' + str(len(daysplt))) - # At this poing daysplt have: + # At this poing daysplt have one of these: # # list_with_days[ # list_with_total_time of_each_type_of_event[ # uptime, downtime_ok, downtime_bad ]] + # + # list_with_days[ + # list_with_total_counter of_each_type_of_event[ + # startup, shutdown_ok, shutdown_bad ]] # Matplotlib requires stack with slices # # y - # | uptime uptime uptime + # | up up up # | down_ok down_ok down_ok # | down_bad down_bad down_bad # |----------------------------------x # | day1 day2 dayN # Get each state values slice from each day - days = {'uptime': [], 'down_ok': [], 'down_bad': []} + days = {'up': [], 'down_ok': [], 'down_bad': []} for i in daysplt: - if not i: i = [0, 0, 0] # Set empty - days['uptime'].append(i[0]) + days['up'].append(i[0]) days['down_ok'].append(i[1]) days['down_bad'].append(i[2]) @@ -216,24 +237,44 @@ def main(): plt.figure(figsize=(arg.width, arg.height)) - # Old bar plot - #width = 0.9 # column size - #plt.bar(ind, days['uptime'], width, color='green', label='Uptime') - #plt.bar(ind, days['down_ok'], width, color='grey', label='Downtime OK', bottom=days['uptime']) - #plt.bar(ind, days['down_bad'], width, color='black', label='Downtime BAD', bottom=[i+j for i, j in zip(days['uptime'], days['down_ok'])]) + if arg.report_events: + plt.ylabel('Counter') + plt.title('Events per state by Day') + rlabel = ['Startup', 'Shutdown Ok', 'Shutdown Bad'] + width = 0.42 # column size + + # Set position of bar on X axis + pst1 = np.arange(len(ind)) + pst2 = [x + width for x in pst1] + + plt.bar(pst1, days['up'], width, color='forestgreen', label=rlabel[0], edgecolor='white') + plt.bar(pst2, days['down_ok'], width, color='grey', label=rlabel[1], edgecolor='white', bottom=days['down_bad']) + plt.bar(pst2, days['down_bad'], width, color='black', label=rlabel[2], edgecolor='white') + + ind = ind + width / 2 + + else: + plt.ylabel('Hours') + plt.title('Hours per State by Day') + plt.yticks(np.arange(0, 25, 2)) + plt.ylim(top=26) + rlabel = ['Uptime', 'Down Ok', 'Down Bad'] + + # Old bar plot + #width = 0.9 # column size + #plt.bar(ind, days['up'], width, color='forestgreen', label=rlabel[0]) + #plt.bar(ind, days['down_ok'], width, color='grey', label=rlabel[1], bottom=days['up']) + #plt.bar(ind, days['down_bad'], width, color='black', label=rlabel[2], bottom=[i+j for i, j in zip(days['up'], days['down_ok'])]) + + plt.plot(ind, days['up'], linewidth=2, marker='o', color='forestgreen', label=rlabel[0]) + plt.plot(ind, days['down_ok'], linewidth=2, marker='o', color='grey', linestyle='--', label=rlabel[1]) + plt.plot(ind, days['down_bad'], linewidth=2, marker='o', color='black', linestyle=':', label=rlabel[2]) - plt.plot(ind, days['uptime'], linewidth=2, marker='o', color='green', label='Uptime') - plt.plot(ind, days['down_ok'], linewidth=2, marker='o', color='grey', label='Down Ok') - plt.plot(ind, days['down_bad'], linewidth=2, marker='o', color='black', label='Down Bad') + plt.grid(color='lightblue', linestyle='--', linewidth=0.5, axis='x') - plt.ylabel('Hours') - plt.title('Hours per State by Day') plt.xticks(ind, xlegend, rotation=85, ha="center") plt.margins(y=0, x=0.01) - plt.yticks(np.arange(0, 25, 2)) - plt.ylim(top=26) plt.grid(color='lightgrey', linestyle='--', linewidth=0.5, axis='y') - plt.grid(color='lightblue', linestyle='--', linewidth=0.5, axis='x') plt.tight_layout() cfig = plt.get_current_fig_manager() cfig.canvas.set_window_title("Tuptime") From 48be889b74e5665dbe0f1201663f00151ddf8f54 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sun, 8 Nov 2020 12:55:56 +0100 Subject: [PATCH 07/37] Expect cm in width and height arguments --- misc/scripts/tuptime-barchart.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/misc/scripts/tuptime-barchart.py b/misc/scripts/tuptime-barchart.py index ea2775f2..1a23c9a3 100644 --- a/misc/scripts/tuptime-barchart.py +++ b/misc/scripts/tuptime-barchart.py @@ -40,9 +40,9 @@ def get_arguments(): parser.add_argument( '-H', '--height', dest='height', - default=6, + default=13, action='store', - help='window height', + help='window height in cm', type=int ) parser.add_argument( @@ -56,9 +56,9 @@ def get_arguments(): parser.add_argument( '-W', '--width', dest='width', - default=8, + default=17, action='store', - help='window width', + help='window width in cm', type=int ) parser.add_argument( @@ -193,7 +193,7 @@ def main(): # Add to events list per day daysplit_events.append(l_row) - print('Got range --->\t' + str(nran) + ' with ' + str(len([i for i in daysplit_events if i != [0, 0, 0]])) + ' events') + print(str(nran) + ' range --->\t' + str(len([i for i in daysplit_events if i != [0, 0, 0]])) + ' events') # Per day, get total value for each type of event if arg.report_events: @@ -235,11 +235,15 @@ def main(): ind = np.arange(len(daysplt)) # number of days on x - plt.figure(figsize=(arg.width, arg.height)) + # Set width and height from inches to cm + plt.figure(figsize=((arg.width / 2.54), (arg.height / 2.54))) if arg.report_events: plt.ylabel('Counter') plt.title('Events per state by Day') + maxv = max(i for v in days.values() for i in v) # Get max value on all ranges + plt.yticks(np.arange(0, (maxv + 1), 1)) + plt.ylim(top=(maxv + 1)) rlabel = ['Startup', 'Shutdown Ok', 'Shutdown Bad'] width = 0.42 # column size From b4b9a5d6a2efe94b44518dd9da153328cf661fd9 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Mon, 9 Nov 2020 17:49:20 +0100 Subject: [PATCH 08/37] Fix typo --- misc/scripts/tuptime-barchart.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/scripts/tuptime-barchart.py b/misc/scripts/tuptime-barchart.py index 1a23c9a3..b4953ef5 100644 --- a/misc/scripts/tuptime-barchart.py +++ b/misc/scripts/tuptime-barchart.py @@ -239,7 +239,7 @@ def main(): plt.figure(figsize=((arg.width / 2.54), (arg.height / 2.54))) if arg.report_events: - plt.ylabel('Counter') + plt.ylabel('Events') plt.title('Events per state by Day') maxv = max(i for v in days.values() for i in v) # Get max value on all ranges plt.yticks(np.arange(0, (maxv + 1), 1)) From b48810ddf476c7be995bbe7c17ad04e64fe3ac75 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Mon, 9 Nov 2020 17:49:42 +0100 Subject: [PATCH 09/37] Bump version --- src/tuptime | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tuptime b/src/tuptime index 724a1256..a1ecaa61 100644 --- a/src/tuptime +++ b/src/tuptime @@ -19,11 +19,12 @@ keeping it between restarts""" import sys, os, argparse, locale, platform, signal, logging, sqlite3, time from datetime import datetime +# On os_bsd(): import subprocess DB_FILE = '/var/lib/tuptime/tuptime.db' DATE_FORMAT = '%X %x' -__version__ = '5.0.1' +__version__ = '5.0.2' # Terminate when SIGPIPE signal is received signal.signal(signal.SIGPIPE, signal.SIG_DFL) From 26b42d0dac80f3aa8f1feb0c84aea1018e8ea9bb Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Mon, 9 Nov 2020 17:50:37 +0100 Subject: [PATCH 10/37] Use subprocess module on BSDs instead of os.popen --- src/tuptime | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/tuptime b/src/tuptime index a1ecaa61..1435492d 100644 --- a/src/tuptime +++ b/src/tuptime @@ -269,14 +269,13 @@ def get_os_values(): """Get values from BSD""" logging.info('System = BSD') + import subprocess try: sis['btime'] = time.clock_gettime(time.CLOCK_REALTIME) - time.clock_gettime(time.CLOCK_MONOTONIC) except Exception as exp: logging.info('Old btime assignment. %s', str(exp)) - sysctl_out = os.popen('sysctl -n kern.boottime').read() - # # import subprocess - # # sysctl_out = subprocess.check_output(['sysctl', '-n', 'kern.boottime'], timeout=1, text=True) + sysctl_out = subprocess.run(['sysctl', '-n', 'kern.boottime'], stdout=subprocess.PIPE, text=True, check=True).stdout # Some BSDs report the value assigned to 'sec', others do it directly if 'sec' in sysctl_out: # FreeBSD, Darwin sis['btime'] = sysctl_out.split(' sec = ')[1].split(',')[0] @@ -304,9 +303,7 @@ def get_os_values(): sis['rntime'] = sis['uptime'] try: - # # import subprocess - # # sysctl_out = subprocess.check_output(['sysctl', '-xn', 'kern.boot_id'], timeout=1, text=True) - sysctl_out = os.popen('sysctl -xn kern.boot_id 2>&1').read() + sysctl_out = subprocess.run(['sysctl', '-xn', 'kern.boot_id'], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True, check=False).stdout if 'Dump' in sysctl_out: sis['bootid'] = sysctl_out.split('Dump:')[-1].rstrip() else: From a229d07d47899fa3cf8359ba3c5fa3bc5a66b8e2 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Mon, 9 Nov 2020 17:50:45 +0100 Subject: [PATCH 11/37] Fix typo --- src/tuptime | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tuptime b/src/tuptime index 1435492d..a87b98e8 100644 --- a/src/tuptime +++ b/src/tuptime @@ -363,10 +363,10 @@ def get_os_values(): for key in sis: if key in ('btime', 'uptime', 'rntime'): if sis[key] is None: - logging.error('%s value unallocate from system. Can\'t continue.', str(sis[key])) + logging.error('"%s" value unallocate from system. Can\'t continue.', str(key)) sys.exit(-1) if key in ('uptime', 'rntime') and float(sis[key]) < 0: - logging.warning('Reset invalid %s value \"%s\"', str(key), str(sis[key])) + logging.warning('Reset invalid "%s" value "%s"', str(key), str(sis[key])) if key == 'uptime': sis['uptime'] = 1 if key == 'rntime': sis['rntime'] = 1 From 277ecf3bffaeee6692aabadce8e34c31e97ed19c Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Thu, 12 Nov 2020 20:55:47 +0100 Subject: [PATCH 12/37] Typo datetime/timestamp --- README.md | 2 +- misc/scripts/README.txt | 2 +- misc/scripts/tuptime-barchart.py | 4 +-- misc/scripts/tuptime_modify.py | 18 +++++----- src/man/tuptime.1 | 21 ++++++------ src/tuptime | 31 ++++++++--------- tuptime-manual.txt | 57 ++++++++++++++++---------------- 7 files changed, 69 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index aa5a58d5..ca640ef1 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ A few days later: Swich to -t | --table option: - No. Startup Date Uptime Shutdown Date End Downtime + No. Startup T. Uptime Shutdown T. End Downtime 1 10:15:27 08/08/15 42s 10:16:09 08/08/15 OK 16s 2 10:16:26 08/08/15 49s 10:17:15 08/08/15 OK 16s diff --git a/misc/scripts/README.txt b/misc/scripts/README.txt index a25809f5..810d0bb1 100644 --- a/misc/scripts/README.txt +++ b/misc/scripts/README.txt @@ -11,7 +11,7 @@ tuptime_join.py tuptime_modify.py Modify registers keeping nearest values in sycn. - Allow change 'end status', 'startup date' and 'shutdown date'. + Allow change 'end status', 'startup timestamp' and 'shutdown timestamp'. diff --git a/misc/scripts/tuptime-barchart.py b/misc/scripts/tuptime-barchart.py index b4953ef5..fce00714 100644 --- a/misc/scripts/tuptime-barchart.py +++ b/misc/scripts/tuptime-barchart.py @@ -94,8 +94,8 @@ def date_check(arg): begin_date = begin_date.replace(hour=0, minute=0, second=0).strftime("%Y-%m-%d %H:%M:%S") end_date = end_date.replace(hour=23, minute=59, second=59).strftime("%Y-%m-%d %H:%M:%S") - print('Begin date:\t' + str(begin_date)) - print('End date:\t' + str(end_date)) + print('Begin datetime:\t' + str(begin_date)) + print('End datetime:\t' + str(end_date)) return([begin_date, end_date]) diff --git a/misc/scripts/tuptime_modify.py b/misc/scripts/tuptime_modify.py index ecdd9602..fd52f5a3 100644 --- a/misc/scripts/tuptime_modify.py +++ b/misc/scripts/tuptime_modify.py @@ -2,19 +2,19 @@ # -*- coding: utf-8 -*- ''' -This script modify the "Startup Date", "Shutdown Date" and "End Status" on -Tuptime database keeping the other values around in sync. +This script modify the "Startup Timestamp", "Shutdown Timestamp" and +"End Status" on Tuptime database keeping the other values around in sync. -Increase 60 secs the startup date on register number 1: +Increase 60 secs the startup datetime on register number 1: tuptime_modify.py -c startup -r 1 -s 60 -Decrease 100 secs the startup date on register number 4 on other file: +Decrease 100 secs the startup datetime on register number 4 on other file: tuptime_modify.py -c startup -r 4 -s -100 -f /tmp/test.db -Increase 30 secs the shutdown date on register number 12: +Increase 30 secs the shutdown datetime on register number 12: tuptime_modify.py -c shutdown -r 12 -s 60 -Decrease 300 secs the shutdown date on register number 47 with verbose: +Decrease 300 secs the shutdown datetime on register number 47 with verbose: tuptime_modify.py -c shutdown -r 47 -s -300 -v Swich end status value on register 54: @@ -47,7 +47,7 @@ def get_arguments(): type=str, required=True, choices=['startup', 'shutdown', 'endst'], - help='change startup or shutdown date time []' + help='change startup or shutdown datetime []' ) parser.add_argument( '-f', '--filedb', @@ -127,7 +127,7 @@ def fix_endst(arg, reg, conn, modt, orgt): def fix_shutdown(arg, reg, conn, modt, orgt): - """Modify shutdown date register""" + """Modify shutdown datetime register""" # Last row have None values if orgt['offbtime'] is None and orgt['downtime'] is None: @@ -166,7 +166,7 @@ def fix_shutdown(arg, reg, conn, modt, orgt): def fix_startup(arg, reg, conn, modt, orgt, modp, orgp): - """Modify startup date register""" + """Modify startup datetime register""" modt['btime'] = orgt['btime'] + arg.seconds modt['uptime'] = orgt['uptime'] - arg.seconds diff --git a/src/man/tuptime.1 b/src/man/tuptime.1 index 5cfb52f5..75f3220d 100644 --- a/src/man/tuptime.1 +++ b/src/man/tuptime.1 @@ -1,10 +1,10 @@ -.TH TUPTIME 1 "Oct 2020" "5.0.1" "Linux Manual" +.TH TUPTIME 1 "Nov 2020" "5.0.2" "Linux Manual" .SH NAME tuptime \- Report historical and statistical real time of the system, keeping it between restarts. Total uptime. .SH SYNOPSIS -tuptime [{\-h | \-\-help}] [{\-A | \-\-at}=] [{\-b | \-\-bootid}] [{\-c | \-\-csv}] [{\-d | \-\-date}=] [\-e | \-\-dec=] [{\-f | \-\-filedb}=] [{\-g | \-\-graceful}] [{\-i | \-\-invert}] [{\-k | \-\-kernel}] [{\-l | \-\-list}] [{\-n | \-\-noup}] [{\-o | \-\-order}=[u|r|s|e|d|k]] [{\-p | \-\-power}] [{\-r | \-\-reverse}] [{\-s | \-\-seconds}] [{\-S | \-\-since}=] [{\-t | \-\-table}] [\-\-tat=] [\-\-tsince=] [\-\-tuntil=] [{\-U | \-\-until}=] [{\-v | \-\-verbose}] [{\-V | \-\-version}] [{\-x | \-\-silent}] +tuptime [{\-h | \-\-help}] [{\-A | \-\-at}=] [{\-b | \-\-bootid}] [{\-c | \-\-csv}] [{\-d | \-\-date}=] [\-e | \-\-dec=] [{\-f | \-\-filedb}=] [{\-g | \-\-graceful}] [{\-i | \-\-invert}] [{\-k | \-\-kernel}] [{\-l | \-\-list}] [{\-n | \-\-noup}] [{\-o | \-\-order}=[u|r|s|e|d|k]] [{\-p | \-\-power}] [{\-r | \-\-reverse}] [{\-s | \-\-seconds}] [{\-S | \-\-since}=] [{\-t | \-\-table}] [\-\-tat=] [\-\-tsince=] [\-\-tuntil=] [{\-U | \-\-until}=] [{\-v | \-\-verbose}] [{\-V | \-\-version}] [{\-x | \-\-silent}] .SH DESCRIPTION .RS @@ -58,8 +58,8 @@ T} \-c | \-\-csv@T{ Output in csv format T} -\-d | \-\-date TIMESTAMP@T{ -Date format output +\-d | \-\-date DATETM_FORMAT@T{ +Datetime/timestamp format output T} \-e | \-\-dec DECIMALS@T{ Number of decimals in percentages @@ -135,7 +135,7 @@ precedence over this. .RE System startups: .RS -Total number of system startups from since first date available. +Total number of system startups from since first timestamp available. .RE System shutdowns: @@ -145,7 +145,7 @@ Total number of shutdowns done correctly or incorrectly. .RE System life: .RS -Time counter since first startup date available. +Time counter since first startup timestamp available. .RE System uptime: @@ -164,7 +164,7 @@ Time counter with the average time. .RE Current uptime: .RS -Actual time counter and date since registered boot date. +Actual time counter and datetime since registered boot timestamp. .SH EXAMPLES .TP @@ -184,11 +184,12 @@ Add kernel information to the output. Report in csv format. .TP .B tuptime -s -Change default human readable date style and print times in seconds and -dates in epoch. +Change default human readable datetime/timestamp style and print times in +seconds and datetimes in epoch. .TP .B tuptime -d '%H:%M:%S %m-%d-%Y' -Change the date format. By default it's printed based on system locales. +Change the datetime/timestamp format. By default the output use the +configured system locales. .TP .B tuptime --tsince -31557600 Report since one year ago. diff --git a/src/tuptime b/src/tuptime index a87b98e8..269ccc35 100644 --- a/src/tuptime +++ b/src/tuptime @@ -23,7 +23,7 @@ from datetime import datetime DB_FILE = '/var/lib/tuptime/tuptime.db' -DATE_FORMAT = '%X %x' +DATETM_FORMAT = '%X %x' __version__ = '5.0.2' # Terminate when SIGPIPE signal is received @@ -66,10 +66,11 @@ def get_arguments(): ) parser.add_argument( '-d', '--date', - dest='date_format', - default=DATE_FORMAT, + dest='dtm_format', + metavar='DATETM_FORMAT', + default=DATETM_FORMAT, action='store', - help='date format output' + help='datetime/timestamp format output' ) parser.add_argument( '-e', '--dec', @@ -359,7 +360,7 @@ def get_os_values(): logging.error('System = %s not supported', sys.platform) sys.exit(-1) - # Check right allocation of variables before continue + # Check right allocation of core variables before continue for key in sis: if key in ('btime', 'uptime', 'rntime'): if sis[key] is None: @@ -566,7 +567,7 @@ def time_conv(secs): dtm['d'], dtm['h'] = divmod(dtm['h'], 24) dtm['yr'], dtm['d'] = divmod(dtm['d'], 365) - # Build date sentence with this order + # Build datetime sentence with this order for key in ('yr', 'd', 'h', 'm', 's'): # Avoid print empty values at the beginning, except seconds @@ -729,7 +730,7 @@ def format_output(db_rows, arg): row['btime'] = '' else: if not arg.seconds: - row['btime'] = datetime.fromtimestamp(row['btime']).strftime(arg.date_format) + row['btime'] = datetime.fromtimestamp(row['btime']).strftime(arg.dtm_format) if row['uptime'] is False: row['uptime'] = row['rntime'] = row['slptime'] = '' @@ -754,7 +755,7 @@ def format_output(db_rows, arg): row['offbtime'] = '' else: if not arg.seconds: - row['offbtime'] = datetime.fromtimestamp(row['offbtime']).strftime(arg.date_format) + row['offbtime'] = datetime.fromtimestamp(row['offbtime']).strftime(arg.dtm_format) if row['downtime'] is False: row['downtime'] = '' @@ -816,7 +817,7 @@ def print_list(db_rows, last_st, arg): def print_table(db_rows, last_st, arg): """Print values as a table""" - tbl = [['No.', 'Boot ID', 'Startup Date', 'Uptime', 'Running', 'Sleeping', 'Shutdown Date', 'End', 'Downtime', 'Kernel']] + tbl = [['No.', 'Boot ID', 'Startup T.', 'Uptime', 'Running', 'Sleeping', 'Shutdown T.', 'End', 'Downtime', 'Kernel']] align_left, colpad = [], [] side_spaces = 3 @@ -934,7 +935,7 @@ def print_tat(db_rows, sis, last_st, arg): report['startup'] = report['startup'] - last_st if not arg.seconds: - report['at'] = datetime.fromtimestamp(report['at']).strftime(arg.date_format) + report['at'] = datetime.fromtimestamp(report['at']).strftime(arg.dtm_format) report['time'] = time_conv(report['time']) report['time_fwd'] = time_conv(report['time_fwd']) @@ -1000,7 +1001,7 @@ def print_default(db_rows, sis, arg): # Get values from all DB rows cal, shdown, updown, cnt = parse_rows(db_rows, cal, shdown, updown, cnt) - # Max timestamp - until date + # Max timestamp - until datetime # Get rightmost (older) value from last row if arg.tu is not used if tstamp['max'] is None: if db_rows[-1]['offbtime'] is not False: @@ -1008,7 +1009,7 @@ def print_default(db_rows, sis, arg): elif db_rows[-1]['btime'] is not False: tstamp['max'] = db_rows[-1]['btime'] + db_rows[-1]['uptime'] - # Min timestamp - since date + # Min timestamp - since datetime # Get leftmost (newer) value, always btime, from first row value if arg.ts is not used if tstamp['min'] is None: tstamp['min'] = db_rows[0]['btime'] @@ -1038,10 +1039,10 @@ def print_default(db_rows, sis, arg): # Ouput style: Apply human or keep seconds if not arg.seconds: if tstamp['max'] is not None: - tstamp['max'] = datetime.fromtimestamp(tstamp['max']).strftime(arg.date_format) + tstamp['max'] = datetime.fromtimestamp(tstamp['max']).strftime(arg.dtm_format) if tstamp['min'] is not None: - tstamp['min'] = datetime.fromtimestamp(tstamp['min']).strftime(arg.date_format) + tstamp['min'] = datetime.fromtimestamp(tstamp['min']).strftime(arg.dtm_format) # Look into the keys to set right values for k in cal: @@ -1051,7 +1052,7 @@ def print_default(db_rows, sis, arg): sis['uptime'] = time_conv(sis['uptime']) sis['rntime'] = time_conv(sis['rntime']) sis['slptime'] = time_conv(sis['slptime']) - sis['btime'] = datetime.fromtimestamp(sis['btime']).strftime(arg.date_format) + sis['btime'] = datetime.fromtimestamp(sis['btime']).strftime(arg.dtm_format) sys_life = time_conv(sys_life) # Finally print all diff --git a/tuptime-manual.txt b/tuptime-manual.txt index 8d9fd4b0..e388cb5e 100644 --- a/tuptime-manual.txt +++ b/tuptime-manual.txt @@ -1,9 +1,9 @@ ---------------------- Tuptime Manual ---------------------- - version 5.0.1 + version 5.0.2 Ricardo F. - 31/Oct/2020 + 12/Nov/2020 @@ -161,8 +161,8 @@ These are the command line options, no configuration file is used: restrict to this startup number -b, --bootid show boot identifier -c, --csv csv output - -d DATE_FORMAT, --date DATE_FORMAT - date format output + -d DATETM_FORMAT, --date DATETM_FORMAT + datetime/timestamp format output -e DECIMALS, --dec DECIMALS number of decimals in percentages -f FILE, --filedb FILE @@ -224,9 +224,9 @@ These are the command line options, no configuration file is used: tuptime --csv -t --d , --date= - Change the date format. By default it's printed based on system locales. - Allow values are: +-d , --date= + Change the datetime/timestamp format. By default the output use the + configured system locales. Allow values are: %a Weekday as locale’s abbreviated name. %A Weekday as locale’s full name. @@ -372,8 +372,8 @@ These are the command line options, no configuration file is used: -s, --seconds - Change default human readable date style and print times in seconds and - dates in epoch. + Change default human readable datetime/timestamp style and print times in seconds + and datetimes in epoch. Examples: tuptime -s @@ -510,13 +510,13 @@ that value if your requirements are narrow. ================== System startups: - Total number of system startups registered since first date available. + Total number of system startups registered since first timestamp available. System shutdowns: Total number of shutdowns done correctly or incorrectly. System life: - Time counter since first startup date available. + Time counter since first startup timestamp available. System uptime: System downtime: @@ -527,7 +527,7 @@ Average downtime: Time counter with the average time. Current uptime: - Actual time counter and date since registered boot date. + Actual time counter and datetime since registered boot timestamp. Removed on version 5 and equivalent output: @@ -582,11 +582,11 @@ tuptime (bootid text, kernel text) bootid Unique boot identifier (if it exists) -btime Startup date in epoch +btime Startup timestamp in epoch uptime Uptime seconds rntime Running time seconds slptime Sleeping time seconds -offbtime Shutdown date in epoch +offbtime Shutdown timestamp in epoch endst Type of shutdown [1 ok | 0 bad] downtime Downtime seconds kernel Name of the kernel @@ -613,16 +613,17 @@ Large jumps over the date and time in a system can cause problems, expecially when the uptime value is low. Take care of the harware clock RTC (if the system have), or how the operating -system initializes their clock at startup. Tuptime register the date reported by -the system at first execution after boot and use it to calculate the previous -shutdown time and the current uptime value. The command 'who -b' do more less -the same. - -If the system starts with a incorrect date and time and some external time sync is -used, like ntpd or timesyncd, a few time after boot the startup date reported by -the system may change. This behaviour is also related with adjustments performed by -adjtime(3), systems running inside virtualized enviroments, servers with high load or -with high disk I/O, wrong computation of jiffies / HZ and the problema of lost ticks. +system initializes their clock at startup. Tuptime register the timestamp +reported by the system at first execution after boot and use it to calculate +the previous shutdown time and the current uptime value. The command 'who -b' +do more less the same. + +If the system starts with a incorrect datetime and some external time sync is +used, like ntpd or timesyncd, a few time after boot the startup datetime reported +by the system may change. This behaviour is also related with adjustments +performed by adjtime(3), systems running inside virtualized enviroments, servers +with high load or with high disk I/O, wrong computation of jiffies / HZ and the +problema of lost ticks. A slightly drift is compensate over the uptime value, but a very high drift can cause inconsistent registers and output, for example, Raspberry Pi don't have any clock and @@ -696,7 +697,7 @@ Seconds equivalences: 1 day 86400 seconds 1 hour 3600 seconds -Convert human date to epoch: +Convert human datetime to epoch: date --date="JAN-18-2018" +%s date --date="20-JAN-18" +%s date --date="2018-01-20 16:21:42" +%s @@ -705,10 +706,10 @@ Convert human date to epoch: date --date="1 year ago" +%s date --date="now" +%s -Convert epoch to human date: +Convert epoch to human datetime: date --date="@1516748400" -More info about date input formats: +More info about datetime input formats: man date 'https://www.gnu.org/software/coreutils/manual/html_node/ Date-input-formats.html#Date-input-formats' @@ -744,7 +745,7 @@ If the system have configured a time zone with daylight saving time (DST), to avoid problems when the time change, the real time clock (RTC) should have set to universal time coordinated (UTC), not local time. Check it with 'timedatectl' command. Reports involving DST changes are completely right. -The system current local time zone is the reference for all dates printed. +The system current local time zone is the reference for all timestamps printed. https://tldp.org/HOWTO/Clock-2.html The name of the tool is based on the contraction of the words Total Uptime. From 2dee962b5d057c72ee189bfe1754c1e20bd9e45b Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Wed, 18 Nov 2020 20:10:46 +0100 Subject: [PATCH 13/37] Print bad shutdown until next event, not only next day --- misc/scripts/tuptime-barchart.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/misc/scripts/tuptime-barchart.py b/misc/scripts/tuptime-barchart.py index fce00714..89ecd07e 100644 --- a/misc/scripts/tuptime-barchart.py +++ b/misc/scripts/tuptime-barchart.py @@ -136,7 +136,7 @@ def main(): daysplt = [] # List for all day splits with their events ftmp = tempfile.NamedTemporaryFile().name # File to store Tuptime csv - bad = None + shutst = None # Iterate over each element in (since, until) list for nran, _ in enumerate(date_list): @@ -159,8 +159,9 @@ def main(): l_row = [0, 0, 0] # Events in csv rows # Control how was the shutdown - if (row[0] == 'Shutdown') and (row[1] == 'BAD'): - bad = True + if (row[0] == 'Shutdown'): + if (row[1] == 'BAD') : shutst = 'BAD' + if (row[1] == 'OK') : shutst = 'OK' if arg.report_events: # Populate list with (startup, shutdown ok, shutdown bad) @@ -170,11 +171,10 @@ def main(): l_row[0] = 1 if row[0] == 'Shutdown' and row[2] == 'at': - if bad is True: + if shutst == 'BAD': l_row[2] = 1 else: l_row[1] = 1 - bad = False else: # Populate list with (uptime, downtime ok, downtime bad) @@ -184,11 +184,10 @@ def main(): l_row[0] = int(row[1]) if row[0] == 'Downtime': - if bad is True: + if shutst == 'BAD': l_row[2] = int(row[1]) else: l_row[1] = int(row[1]) - bad = False # Add to events list per day daysplit_events.append(l_row) From 3c88c2bc62b77cf3f2384f140233af5d76d7901e Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Wed, 18 Nov 2020 20:12:30 +0100 Subject: [PATCH 14/37] Update standards version to 4.5.1 --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 81b4a5bb..904baf1d 100644 --- a/debian/control +++ b/debian/control @@ -4,7 +4,7 @@ Priority: optional Maintainer: Ricardo Fraile Build-Depends: debhelper-compat (= 13) Rules-Requires-Root: no -Standards-Version: 4.5.0 +Standards-Version: 4.5.1 Homepage: https://github.com/rfrail3/tuptime Package: tuptime From adc43a1e43cdc2a7717eaa7f167bf66226f93a09 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Thu, 19 Nov 2020 19:14:55 +0100 Subject: [PATCH 15/37] Merge downtime on default report --- misc/scripts/tuptime-barchart.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/misc/scripts/tuptime-barchart.py b/misc/scripts/tuptime-barchart.py index 89ecd07e..d19c2621 100644 --- a/misc/scripts/tuptime-barchart.py +++ b/misc/scripts/tuptime-barchart.py @@ -159,9 +159,9 @@ def main(): l_row = [0, 0, 0] # Events in csv rows # Control how was the shutdown - if (row[0] == 'Shutdown'): - if (row[1] == 'BAD') : shutst = 'BAD' - if (row[1] == 'OK') : shutst = 'OK' + if row[0] == 'Shutdown': + if row[1] == 'BAD': shutst = 'BAD' + if row[1] == 'OK': shutst = 'OK' if arg.report_events: # Populate list with (startup, shutdown ok, shutdown bad) @@ -261,17 +261,18 @@ def main(): plt.title('Hours per State by Day') plt.yticks(np.arange(0, 25, 2)) plt.ylim(top=26) - rlabel = ['Uptime', 'Down Ok', 'Down Bad'] + rlabel = ['Uptime', 'Downtime'] + + # Merge all downtimes + days['down'] = [x + y for x, y in zip(days['down_ok'], days['down_bad'])] # Old bar plot #width = 0.9 # column size #plt.bar(ind, days['up'], width, color='forestgreen', label=rlabel[0]) - #plt.bar(ind, days['down_ok'], width, color='grey', label=rlabel[1], bottom=days['up']) - #plt.bar(ind, days['down_bad'], width, color='black', label=rlabel[2], bottom=[i+j for i, j in zip(days['up'], days['down_ok'])]) + #plt.bar(ind, days['down'], width, color='grey', label=rlabel[1], bottom=days['up']) plt.plot(ind, days['up'], linewidth=2, marker='o', color='forestgreen', label=rlabel[0]) - plt.plot(ind, days['down_ok'], linewidth=2, marker='o', color='grey', linestyle='--', label=rlabel[1]) - plt.plot(ind, days['down_bad'], linewidth=2, marker='o', color='black', linestyle=':', label=rlabel[2]) + plt.plot(ind, days['down'], linewidth=2, marker='o', color='grey', linestyle='--', label=rlabel[1]) plt.grid(color='lightblue', linestyle='--', linewidth=0.5, axis='x') From f79f2c20a0ba2b589b9ea14e4af7f2d7ebf2c505 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Thu, 19 Nov 2020 21:12:52 +0100 Subject: [PATCH 16/37] New scatter plot --- misc/scripts/README.txt | 6 +- .../{tuptime-barchart.py => tuptime-plot1.py} | 0 misc/scripts/tuptime-plot2.py | 189 ++++++++++++++++++ 3 files changed, 194 insertions(+), 1 deletion(-) rename misc/scripts/{tuptime-barchart.py => tuptime-plot1.py} (100%) create mode 100644 misc/scripts/tuptime-plot2.py diff --git a/misc/scripts/README.txt b/misc/scripts/README.txt index 810d0bb1..5dd0554b 100644 --- a/misc/scripts/README.txt +++ b/misc/scripts/README.txt @@ -38,7 +38,11 @@ db-tuptime-migrate-4.0-to-5.0.sh ____Plots____ -tuptime-barchart.py +tuptime-plot1.py Graph a plot with the number of hours (default) or events (-x swich) per state along each day. It gets the info from tuptime csv output. Playground script. + +tuptime-plot2.py + Graph a plot with the state events per hour along each day. It gets + the info from tuptime csv output. Playground script. diff --git a/misc/scripts/tuptime-barchart.py b/misc/scripts/tuptime-plot1.py similarity index 100% rename from misc/scripts/tuptime-barchart.py rename to misc/scripts/tuptime-plot1.py diff --git a/misc/scripts/tuptime-plot2.py b/misc/scripts/tuptime-plot2.py new file mode 100644 index 00000000..34df4ff6 --- /dev/null +++ b/misc/scripts/tuptime-plot2.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import subprocess, csv, argparse, tempfile +from datetime import datetime, timedelta +from matplotlib.lines import Line2D +import matplotlib.pyplot as plt +import matplotlib.dates as mdates +import dateutil.parser + + +def get_arguments(): + """Get arguments from command line""" + + parser = argparse.ArgumentParser() + parser.add_argument( + '-b', '--bdate', + dest='bdate', + action='store', + help='begin date to plot, format:"Y-m-d"', + type=str + ) + parser.add_argument( + '-e', '--edate', + dest='edate', + action='store', + help='end date to plot, format:"Y-m-d" (default today)', + type=str + ) + parser.add_argument( + '-f', '--filedb', + dest='dbfile', + default=None, + action='store', + help='database file' + ) + parser.add_argument( + '-H', '--height', + dest='height', + default=13, + action='store', + help='window height in cm', + type=int + ) + parser.add_argument( + '-p', '--pastdays', + dest='pdays', + default=7, + action='store', + help='past days before edate to plot (default is 7)', + type=int + ) + parser.add_argument( + '-W', '--width', + dest='width', + default=17, + action='store', + help='window width in cm', + type=int + ) + arg = parser.parse_args() + return arg + + +def date_check(arg): + """Check and clean dates""" + + # Set user provided or default end date + if arg.edate: + end_date = dateutil.parser.parse(arg.edate) + else: + end_date = datetime.today() + print('Default end:\tnow') + + # Set user provided or default begind date. Days ago... + if arg.bdate: + begin_date = dateutil.parser.parse(arg.bdate) + else: + begin_date = end_date - timedelta(days=arg.pdays) + print('Default begin:\tsince ' + str(arg.pdays) + ' days ago') + + + # Adjust date to the start or end time range and set the format + begin_date = begin_date.replace(hour=0, minute=0, second=0).strftime("%Y-%m-%d %H:%M:%S") + end_date = end_date.replace(hour=23, minute=59, second=59).strftime("%Y-%m-%d %H:%M:%S") + + print('Begin datetime:\t' + str(begin_date)) + print('End datetime:\t' + str(end_date)) + + return([begin_date, end_date]) + + + +def main(): + """Core logic""" + + arg = get_arguments() + date_limits = date_check(arg) + + ftmp = tempfile.NamedTemporaryFile().name # File to store Tuptime csv + + # Get datetime objects from date limits in timestamp format + tsince = str(int(dateutil.parser.parse(date_limits[0]).timestamp())) + tuntil = str(int(dateutil.parser.parse(date_limits[1]).timestamp())) + + with open(ftmp, "wb", 0) as out: + if arg.dbfile: # If a file is passed, avoid update it + subprocess.call(["tuptime", "-tsc", "--tsince", tsince, "--tuntil", tuntil, "-f", arg.dbfile, "-n"], stdout=out) + else: + subprocess.call(["tuptime", "-tsc", "--tsince", tsince, "--tuntil", tuntil], stdout=out) + + tstamp = [] # startup and shutdown timestamps + color = [] # colors + + # Parse csv file + + with open(ftmp) as csv_file: + csv_reader = csv.reader(csv_file, delimiter=',') + + for row in csv_reader: + + if row[0] == 'No.': + continue + + #print('Startup T.: ' + row[1]) + #print('Uptime: ' + row[2]) + #print('Shutdown T.: ' + row[3]) + #print('End: ' + row[4]) + #print('Downtime: ' + row[5]) + #print('-') + + if row[1] != '' and row[3] != '': + tstamp.append(row[1]) + color.append('forestgreen') + + tstamp.append(row[3]) + if row[4] == 'BAD': + color.append('black') + else: + color.append('grey') + + # Convert to datetime object + tstamp = [datetime.fromtimestamp(int(elem)) for elem in tstamp] + + # Reset date allows position circles inside the same 00..24 range on y-axis + y = [elem.replace(year=1970, month=1, day=1) for elem in tstamp] + + # Reset hour allows position circles straight over the date tick on x-axis + x = [elem.replace(hour=00, minute=00, second=00) for elem in tstamp] + + # Set scatter plot values + plt.scatter(x, y, s=200, color=color, edgecolors='white', alpha=0.8, marker="X") + + # Format axes: + plt.gcf().autofmt_xdate() + axs = plt.gca() + + # X as days and defined limits + 12h of margin + axs.xaxis.set_major_formatter(mdates.DateFormatter('%D')) + axs.xaxis.set_major_locator(mdates.DayLocator()) + lbegin = datetime.strptime(date_limits[0], '%Y-%m-%d %H:%M:%S') - timedelta(hours=12) + lend = datetime.strptime(date_limits[1], '%Y-%m-%d %H:%M:%S') + timedelta(hours=12) + plt.xlim(lbegin, lend) + + # Y as 24 hours range + axs.yaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) + axs.yaxis.set_major_locator(mdates.HourLocator(byhour=range(0, 24, 2))) + plt.ylim([datetime(1970, 1, 1, 00, 00), datetime(1970, 1, 1, 23, 59, 59)]) + + # Set legend + plt.legend(handles=[Line2D([0], [0], marker='X', color='w', alpha=0.8, label='Startup', markerfacecolor='forestgreen', markersize=10), + Line2D([0], [0], marker='X', color='w', alpha=0.8, label='Shutdown Ok', markerfacecolor='grey', markersize=10), + Line2D([0], [0], marker='X', color='w', alpha=0.8, label='Shutdown Bad', markerfacecolor='black', markersize=10)]) + + axs.set_axisbelow(True) + axs.invert_yaxis() + axs.grid(True) + + plt.ylabel('Day Time') + plt.title('Events on Time by Day') + plt.margins(y=0, x=0.01) + plt.grid(color='lightgrey', linestyle='--', linewidth=0.9, axis='y') + plt.tight_layout() + cfig = plt.get_current_fig_manager() + cfig.canvas.set_window_title("Tuptime") + plt.show() + +if __name__ == "__main__": + main() From 400a180dfa3b105ef42cbeb05298857fe7f4fece Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Fri, 20 Nov 2020 19:11:41 +0100 Subject: [PATCH 17/37] Fix typo --- misc/scripts/tuptime-plot1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/scripts/tuptime-plot1.py b/misc/scripts/tuptime-plot1.py index d19c2621..c00d8fda 100644 --- a/misc/scripts/tuptime-plot1.py +++ b/misc/scripts/tuptime-plot1.py @@ -206,7 +206,7 @@ def main(): print('Ranges got:\t' + str(len(daysplt))) - # At this poing daysplt have one of these: + # At this point daysplt have one of these: # # list_with_days[ # list_with_total_time of_each_type_of_event[ From 7b4ed6c4923984ae9b9901a7c03fde7508be0788 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Fri, 20 Nov 2020 19:11:56 +0100 Subject: [PATCH 18/37] Add pie plot --- misc/scripts/README.txt | 5 +- misc/scripts/tuptime-plot2.py | 128 ++++++++++++++++++++++------------ 2 files changed, 85 insertions(+), 48 deletions(-) diff --git a/misc/scripts/README.txt b/misc/scripts/README.txt index 5dd0554b..71c2ac3f 100644 --- a/misc/scripts/README.txt +++ b/misc/scripts/README.txt @@ -44,5 +44,6 @@ tuptime-plot1.py Playground script. tuptime-plot2.py - Graph a plot with the state events per hour along each day. It gets - the info from tuptime csv output. Playground script. + Graph a plot with the state events per hour along each day (default) + or accumulated events per hour (-x swich). It gets the info from + tuptime csv output. Playground script. diff --git a/misc/scripts/tuptime-plot2.py b/misc/scripts/tuptime-plot2.py index 34df4ff6..a40c096a 100644 --- a/misc/scripts/tuptime-plot2.py +++ b/misc/scripts/tuptime-plot2.py @@ -3,7 +3,7 @@ import subprocess, csv, argparse, tempfile from datetime import datetime, timedelta -from matplotlib.lines import Line2D +from collections import Counter import matplotlib.pyplot as plt import matplotlib.dates as mdates import dateutil.parser @@ -58,6 +58,13 @@ def get_arguments(): help='window width in cm', type=int ) + parser.add_argument( + '-x', + dest='report_pie', + action='store_true', + default=False, + help='swich to pie report with accumulated hours' + ) arg = parser.parse_args() return arg @@ -97,28 +104,25 @@ def main(): arg = get_arguments() date_limits = date_check(arg) - ftmp = tempfile.NamedTemporaryFile().name # File to store Tuptime csv + ftmp = tempfile.NamedTemporaryFile().name # For Tuptime csv file + tst = {'up': [], 'down': [], 'down_ok': [], 'down_bad': []} # Store events list on range # Get datetime objects from date limits in timestamp format tsince = str(int(dateutil.parser.parse(date_limits[0]).timestamp())) tuntil = str(int(dateutil.parser.parse(date_limits[1]).timestamp())) + # Query tuptime for every (since, until) and save output to a file with open(ftmp, "wb", 0) as out: if arg.dbfile: # If a file is passed, avoid update it subprocess.call(["tuptime", "-tsc", "--tsince", tsince, "--tuntil", tuntil, "-f", arg.dbfile, "-n"], stdout=out) else: subprocess.call(["tuptime", "-tsc", "--tsince", tsince, "--tuntil", tuntil], stdout=out) - tstamp = [] # startup and shutdown timestamps - color = [] # colors - # Parse csv file - with open(ftmp) as csv_file: csv_reader = csv.reader(csv_file, delimiter=',') for row in csv_reader: - if row[0] == 'No.': continue @@ -127,59 +131,91 @@ def main(): #print('Shutdown T.: ' + row[3]) #print('End: ' + row[4]) #print('Downtime: ' + row[5]) - #print('-') - if row[1] != '' and row[3] != '': - tstamp.append(row[1]) - color.append('forestgreen') + if row[1] != '': + tst['up'].append(row[1]) - tstamp.append(row[3]) + if row[3] != '': if row[4] == 'BAD': - color.append('black') + tst['down_bad'].append(row[3]) else: - color.append('grey') + tst['down_ok'].append(row[3]) - # Convert to datetime object - tstamp = [datetime.fromtimestamp(int(elem)) for elem in tstamp] + # Set whole downtimes and convert to datetime object + tst['down'] = tst['down_ok'] + tst['down_bad'] + for state in tst: + tst[state] = [datetime.fromtimestamp(int(elem)) for elem in tst[state]] - # Reset date allows position circles inside the same 00..24 range on y-axis - y = [elem.replace(year=1970, month=1, day=1) for elem in tstamp] + if arg.report_pie: + pie = {'up': [], 'down': []} # One plot for each type - # Reset hour allows position circles straight over the date tick on x-axis - x = [elem.replace(hour=00, minute=00, second=00) for elem in tstamp] + # From datetime, get only hour and add 'h' at the end + for elem in tst['up']: pie['up'].append(str(elem.hour) + str('h')) + for elem in tst['down']: pie['down'].append(str(elem.hour) + str('h')) - # Set scatter plot values - plt.scatter(x, y, s=200, color=color, edgecolors='white', alpha=0.8, marker="X") + # Count elements on list or set None if emtpy + c_down = dict(Counter(pie['down'])) if pie['down'] else {'None': [0]} + c_up = dict(Counter(pie['up'])) if pie['up'] else {'None': [0]} - # Format axes: - plt.gcf().autofmt_xdate() - axs = plt.gca() + # Set two plots and their frame size + _, axs = plt.subplots(1, 2, figsize=((arg.width / 2.54), (arg.height / 2.54))) - # X as days and defined limits + 12h of margin - axs.xaxis.set_major_formatter(mdates.DateFormatter('%D')) - axs.xaxis.set_major_locator(mdates.DayLocator()) - lbegin = datetime.strptime(date_limits[0], '%Y-%m-%d %H:%M:%S') - timedelta(hours=12) - lend = datetime.strptime(date_limits[1], '%Y-%m-%d %H:%M:%S') + timedelta(hours=12) - plt.xlim(lbegin, lend) + # Set values for each pie plot + axs[0].pie([c_up[v] for v in c_up], labels=[k for k in c_up], autopct='%1.1f%%', textprops={'fontsize': 8}) + axs[0].set(aspect="equal", title='Startup') - # Y as 24 hours range - axs.yaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) - axs.yaxis.set_major_locator(mdates.HourLocator(byhour=range(0, 24, 2))) - plt.ylim([datetime(1970, 1, 1, 00, 00), datetime(1970, 1, 1, 23, 59, 59)]) + axs[1].pie([c_down[v] for v in c_down], labels=[k for k in c_down], autopct='%1.1f%%', textprops={'fontsize': 8}) + axs[1].set(aspect="equal", title='Shutdown') - # Set legend - plt.legend(handles=[Line2D([0], [0], marker='X', color='w', alpha=0.8, label='Startup', markerfacecolor='forestgreen', markersize=10), - Line2D([0], [0], marker='X', color='w', alpha=0.8, label='Shutdown Ok', markerfacecolor='grey', markersize=10), - Line2D([0], [0], marker='X', color='w', alpha=0.8, label='Shutdown Bad', markerfacecolor='black', markersize=10)]) + axs[0].text(1, -0.1, str('From ' + str(date_limits[0]) + ' to ' + str(date_limits[1])), size=10, ha="center", transform=axs[0].transAxes) + plt.suptitle("Events per hour", fontsize=14) - axs.set_axisbelow(True) - axs.invert_yaxis() - axs.grid(True) + else: + # Reset date allows position circles inside the same 00..24 range on y-axis + scatt_y = {'up': [], 'down_ok': [], 'down_bad': []} + scatt_y['up'] = [elem.replace(year=1970, month=1, day=1) for elem in tst['up']] + scatt_y['down_ok'] = [elem.replace(year=1970, month=1, day=1) for elem in tst['down_ok']] + scatt_y['down_bad'] = [elem.replace(year=1970, month=1, day=1) for elem in tst['down_bad']] + + # Reset hour allows position circles straight over the date tick on x-axis + scatt_x = {'up': [], 'down_ok': [], 'down_bad': []} + scatt_x['up'] = [elem.replace(hour=00, minute=00, second=00) for elem in tst['up']] + scatt_x['down_ok'] = [elem.replace(hour=00, minute=00, second=00) for elem in tst['down_ok']] + scatt_x['down_bad'] = [elem.replace(hour=00, minute=00, second=00) for elem in tst['down_bad']] + + # Set width and height from inches to cm + plt.figure(figsize=((arg.width / 2.54), (arg.height / 2.54))) + + # Set scatter plot values + plt.scatter(scatt_x['up'], scatt_y['up'], s=200, color='forestgreen', edgecolors='white', alpha=0.8, marker="X", label='Up') + plt.scatter(scatt_x['down_ok'], scatt_y['down_ok'], s=200, color='grey', edgecolors='white', alpha=0.8, marker="X", label='Down ok') + plt.scatter(scatt_x['down_bad'], scatt_y['down_bad'], s=200, color='black', edgecolors='white', alpha=0.8, marker="X", label='Down bad') + + # Format axes: + plt.gcf().autofmt_xdate() + axs = plt.gca() + + # X as days and defined limits + 12h of margin + axs.xaxis.set_major_formatter(mdates.DateFormatter('%D')) + axs.xaxis.set_major_locator(mdates.DayLocator()) + lbegin = datetime.strptime(date_limits[0], '%Y-%m-%d %H:%M:%S') - timedelta(hours=12) + lend = datetime.strptime(date_limits[1], '%Y-%m-%d %H:%M:%S') + timedelta(hours=12) + plt.xlim(lbegin, lend) + + # Y as 24 hours range + axs.yaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) + axs.yaxis.set_major_locator(mdates.HourLocator(byhour=range(0, 24, 2))) + plt.ylim([datetime(1970, 1, 1, 00, 00), datetime(1970, 1, 1, 23, 59, 59)]) + + axs.set_axisbelow(True) + axs.invert_yaxis() + plt.grid(True) + plt.ylabel('Day Time') + plt.title('Events on Time by Day') + plt.margins(y=0, x=0.01) + plt.grid(color='lightgrey', linestyle='--', linewidth=0.9, axis='y') + plt.legend() - plt.ylabel('Day Time') - plt.title('Events on Time by Day') - plt.margins(y=0, x=0.01) - plt.grid(color='lightgrey', linestyle='--', linewidth=0.9, axis='y') plt.tight_layout() cfig = plt.get_current_fig_manager() cfig.canvas.set_window_title("Tuptime") From 2597dcc27c548c987dfebf02ac59cd5e95996393 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Fri, 20 Nov 2020 23:56:50 +0100 Subject: [PATCH 19/37] Order date format --- misc/scripts/tuptime-plot1.py | 10 +++++----- misc/scripts/tuptime-plot2.py | 28 ++++++++++++++-------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/misc/scripts/tuptime-plot1.py b/misc/scripts/tuptime-plot1.py index c00d8fda..77b5ef02 100644 --- a/misc/scripts/tuptime-plot1.py +++ b/misc/scripts/tuptime-plot1.py @@ -20,14 +20,14 @@ def get_arguments(): '-b', '--bdate', dest='bdate', action='store', - help='begin date to plot, format:"Y-m-d"', + help='begin date to plot, format:"d-m-Y"', type=str ) parser.add_argument( '-e', '--edate', dest='edate', action='store', - help='end date to plot, format:"Y-m-d" (default today)', + help='end date to plot, format:"d-m-Y" (default today)', type=str ) parser.add_argument( @@ -91,8 +91,8 @@ def date_check(arg): # Adjust date to the start or end time range and set the format - begin_date = begin_date.replace(hour=0, minute=0, second=0).strftime("%Y-%m-%d %H:%M:%S") - end_date = end_date.replace(hour=23, minute=59, second=59).strftime("%Y-%m-%d %H:%M:%S") + begin_date = begin_date.replace(hour=0, minute=0, second=0).strftime("%d-%b-%Y %H:%M:%S") + end_date = end_date.replace(hour=23, minute=59, second=59).strftime("%d-%b-%Y %H:%M:%S") print('Begin datetime:\t' + str(begin_date)) print('End datetime:\t' + str(end_date)) @@ -120,7 +120,7 @@ def date_range(date_limits): # Convert to epoch dates, pack two of them, begin and end for each split, and create a list with all for reg in range(1, len(dlimit)): ranepo.append([int(dlimit[reg-1].timestamp()), int(dlimit[reg].timestamp())]) - xlegend.append(datetime.fromtimestamp(dlimit[reg-1].timestamp()).strftime('%Y-%m-%d')) + xlegend.append(datetime.fromtimestamp(dlimit[reg-1].timestamp()).strftime('%d-%b-%Y')) print('Ranges on list:\t' + str(len(ranepo))) diff --git a/misc/scripts/tuptime-plot2.py b/misc/scripts/tuptime-plot2.py index a40c096a..83d0dc00 100644 --- a/misc/scripts/tuptime-plot2.py +++ b/misc/scripts/tuptime-plot2.py @@ -17,14 +17,14 @@ def get_arguments(): '-b', '--bdate', dest='bdate', action='store', - help='begin date to plot, format:"Y-m-d"', + help='begin date to plot, format:"d-m-Y"', type=str ) parser.add_argument( '-e', '--edate', dest='edate', action='store', - help='end date to plot, format:"Y-m-d" (default today)', + help='end date to plot, format:"d-m-Y" (default today)', type=str ) parser.add_argument( @@ -88,8 +88,8 @@ def date_check(arg): # Adjust date to the start or end time range and set the format - begin_date = begin_date.replace(hour=0, minute=0, second=0).strftime("%Y-%m-%d %H:%M:%S") - end_date = end_date.replace(hour=23, minute=59, second=59).strftime("%Y-%m-%d %H:%M:%S") + begin_date = begin_date.replace(hour=0, minute=0, second=0).strftime("%d-%b-%Y %H:%M:%S") + end_date = end_date.replace(hour=23, minute=59, second=59).strftime("%d-%b-%Y %H:%M:%S") print('Begin datetime:\t' + str(begin_date)) print('End datetime:\t' + str(end_date)) @@ -154,17 +154,17 @@ def main(): for elem in tst['down']: pie['down'].append(str(elem.hour) + str('h')) # Count elements on list or set None if emtpy - c_down = dict(Counter(pie['down'])) if pie['down'] else {'None': [0]} - c_up = dict(Counter(pie['up'])) if pie['up'] else {'None': [0]} + pie['down'] = dict(Counter(pie['down'])) if pie['down'] else {'None': [0]} + pie['up'] = dict(Counter(pie['up'])) if pie['up'] else {'None': [0]} # Set two plots and their frame size _, axs = plt.subplots(1, 2, figsize=((arg.width / 2.54), (arg.height / 2.54))) # Set values for each pie plot - axs[0].pie([c_up[v] for v in c_up], labels=[k for k in c_up], autopct='%1.1f%%', textprops={'fontsize': 8}) + axs[0].pie([pie['up'][v] for v in pie['up']], labels=[k for k in pie['up']], autopct='%1.1f%%', textprops={'fontsize': 8}, wedgeprops={'alpha':0.85}) axs[0].set(aspect="equal", title='Startup') - axs[1].pie([c_down[v] for v in c_down], labels=[k for k in c_down], autopct='%1.1f%%', textprops={'fontsize': 8}) + axs[1].pie([pie['down'][v] for v in pie['down']], labels=[k for k in pie['down']], autopct='%1.1f%%', textprops={'fontsize': 8}, wedgeprops={'alpha':0.85}) axs[1].set(aspect="equal", title='Shutdown') axs[0].text(1, -0.1, str('From ' + str(date_limits[0]) + ' to ' + str(date_limits[1])), size=10, ha="center", transform=axs[0].transAxes) @@ -187,19 +187,19 @@ def main(): plt.figure(figsize=((arg.width / 2.54), (arg.height / 2.54))) # Set scatter plot values - plt.scatter(scatt_x['up'], scatt_y['up'], s=200, color='forestgreen', edgecolors='white', alpha=0.8, marker="X", label='Up') - plt.scatter(scatt_x['down_ok'], scatt_y['down_ok'], s=200, color='grey', edgecolors='white', alpha=0.8, marker="X", label='Down ok') - plt.scatter(scatt_x['down_bad'], scatt_y['down_bad'], s=200, color='black', edgecolors='white', alpha=0.8, marker="X", label='Down bad') + plt.scatter(scatt_x['up'], scatt_y['up'], s=200, color='forestgreen', edgecolors='white', alpha=0.85, marker="X", label='Up') + plt.scatter(scatt_x['down_ok'], scatt_y['down_ok'], s=200, color='grey', edgecolors='white', alpha=0.85, marker="X", label='Down ok') + plt.scatter(scatt_x['down_bad'], scatt_y['down_bad'], s=200, color='black', edgecolors='white', alpha=0.85, marker="X", label='Down bad') # Format axes: plt.gcf().autofmt_xdate() axs = plt.gca() # X as days and defined limits + 12h of margin - axs.xaxis.set_major_formatter(mdates.DateFormatter('%D')) + axs.xaxis.set_major_formatter(mdates.DateFormatter('%d-%b-%Y')) axs.xaxis.set_major_locator(mdates.DayLocator()) - lbegin = datetime.strptime(date_limits[0], '%Y-%m-%d %H:%M:%S') - timedelta(hours=12) - lend = datetime.strptime(date_limits[1], '%Y-%m-%d %H:%M:%S') + timedelta(hours=12) + lbegin = datetime.strptime(date_limits[0], '%d-%b-%Y %H:%M:%S') - timedelta(hours=12) + lend = datetime.strptime(date_limits[1], '%d-%b-%Y %H:%M:%S') + timedelta(hours=12) plt.xlim(lbegin, lend) # Y as 24 hours range From 08e282b933572034e13d582ebb03e5cc4c83cff2 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sat, 21 Nov 2020 01:18:23 +0100 Subject: [PATCH 20/37] Set right slice order --- misc/scripts/tuptime-plot2.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/misc/scripts/tuptime-plot2.py b/misc/scripts/tuptime-plot2.py index 83d0dc00..83703032 100644 --- a/misc/scripts/tuptime-plot2.py +++ b/misc/scripts/tuptime-plot2.py @@ -149,22 +149,30 @@ def main(): if arg.report_pie: pie = {'up': [], 'down': []} # One plot for each type - # From datetime, get only hour and add 'h' at the end - for elem in tst['up']: pie['up'].append(str(elem.hour) + str('h')) - for elem in tst['down']: pie['down'].append(str(elem.hour) + str('h')) + # From datetime, get only hour + for elem in tst['up']: pie['up'].append(str(elem.hour)) + for elem in tst['down']: pie['down'].append(str(elem.hour)) - # Count elements on list or set None if emtpy - pie['down'] = dict(Counter(pie['down'])) if pie['down'] else {'None': [0]} - pie['up'] = dict(Counter(pie['up'])) if pie['up'] else {'None': [0]} + # Count elements on list or set '0' if emtpy. Get list with items + pie['up'] = dict(Counter(pie['up'])).items() if pie['up'] else [('0', 0)] + pie['down'] = dict(Counter(pie['down'])).items() if pie['down'] else [('0', 0)] + + # Values ordered by first element on list that was key on source dict + pie['up'] = sorted(pie['up'], key=lambda ordr: int(ordr[0])) + pie['down'] = sorted(pie['down'], key=lambda ordr: int(ordr[0])) # Set two plots and their frame size _, axs = plt.subplots(1, 2, figsize=((arg.width / 2.54), (arg.height / 2.54))) # Set values for each pie plot - axs[0].pie([pie['up'][v] for v in pie['up']], labels=[k for k in pie['up']], autopct='%1.1f%%', textprops={'fontsize': 8}, wedgeprops={'alpha':0.85}) + axs[0].pie([v[1] for v in pie['up']], labels=[k[0].rjust(2, '0') + str('h') for k in pie['up']], + autopct='%1.1f%%', startangle=90, counterclock=False, + textprops={'fontsize': 8}, wedgeprops={'alpha':0.85}) axs[0].set(aspect="equal", title='Startup') - axs[1].pie([pie['down'][v] for v in pie['down']], labels=[k for k in pie['down']], autopct='%1.1f%%', textprops={'fontsize': 8}, wedgeprops={'alpha':0.85}) + axs[1].pie([v[1] for v in pie['down']], labels=[str(k[0]).rjust(2, '0') + str('h') for k in pie['down']], + autopct='%1.1f%%', startangle=90, counterclock=False, + textprops={'fontsize': 8}, wedgeprops={'alpha':0.85}) axs[1].set(aspect="equal", title='Shutdown') axs[0].text(1, -0.1, str('From ' + str(date_limits[0]) + ' to ' + str(date_limits[1])), size=10, ha="center", transform=axs[0].transAxes) From ead44e657c3a31e3151cb997d574111361f69e2b Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sat, 21 Nov 2020 01:36:35 +0100 Subject: [PATCH 21/37] Fix margin --- misc/scripts/tuptime-plot2.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/misc/scripts/tuptime-plot2.py b/misc/scripts/tuptime-plot2.py index 83703032..43598675 100644 --- a/misc/scripts/tuptime-plot2.py +++ b/misc/scripts/tuptime-plot2.py @@ -203,12 +203,11 @@ def main(): plt.gcf().autofmt_xdate() axs = plt.gca() - # X as days and defined limits + 12h of margin + # X as days and defined limits with their margin axs.xaxis.set_major_formatter(mdates.DateFormatter('%d-%b-%Y')) axs.xaxis.set_major_locator(mdates.DayLocator()) - lbegin = datetime.strptime(date_limits[0], '%d-%b-%Y %H:%M:%S') - timedelta(hours=12) - lend = datetime.strptime(date_limits[1], '%d-%b-%Y %H:%M:%S') + timedelta(hours=12) - plt.xlim(lbegin, lend) + plt.xlim(datetime.strptime(date_limits[0], '%d-%b-%Y %H:%M:%S') - timedelta(hours=4), + datetime.strptime(date_limits[1], '%d-%b-%Y %H:%M:%S') - timedelta(hours=20)) # Y as 24 hours range axs.yaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) From e30351a2b222cba112d006d893c6f1fc3d237e6f Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sat, 21 Nov 2020 01:37:05 +0100 Subject: [PATCH 22/37] Set auto format on x-axis --- misc/scripts/tuptime-plot1.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/misc/scripts/tuptime-plot1.py b/misc/scripts/tuptime-plot1.py index 77b5ef02..dab6c09d 100644 --- a/misc/scripts/tuptime-plot1.py +++ b/misc/scripts/tuptime-plot1.py @@ -276,7 +276,8 @@ def main(): plt.grid(color='lightblue', linestyle='--', linewidth=0.5, axis='x') - plt.xticks(ind, xlegend, rotation=85, ha="center") + plt.xticks(ind, xlegend) + plt.gcf().autofmt_xdate() plt.margins(y=0, x=0.01) plt.grid(color='lightgrey', linestyle='--', linewidth=0.5, axis='y') plt.tight_layout() From 9060edd84001d9b72157fc31681f4cb77adb2c5e Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sat, 21 Nov 2020 10:26:57 +0100 Subject: [PATCH 23/37] Default size on help output --- misc/scripts/tuptime-plot1.py | 4 ++-- misc/scripts/tuptime-plot2.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/misc/scripts/tuptime-plot1.py b/misc/scripts/tuptime-plot1.py index dab6c09d..c107f56d 100644 --- a/misc/scripts/tuptime-plot1.py +++ b/misc/scripts/tuptime-plot1.py @@ -42,7 +42,7 @@ def get_arguments(): dest='height', default=13, action='store', - help='window height in cm', + help='window height in cm (default 13)', type=int ) parser.add_argument( @@ -58,7 +58,7 @@ def get_arguments(): dest='width', default=17, action='store', - help='window width in cm', + help='window width in cm (default 17)', type=int ) parser.add_argument( diff --git a/misc/scripts/tuptime-plot2.py b/misc/scripts/tuptime-plot2.py index 43598675..a9df1d72 100644 --- a/misc/scripts/tuptime-plot2.py +++ b/misc/scripts/tuptime-plot2.py @@ -39,7 +39,7 @@ def get_arguments(): dest='height', default=13, action='store', - help='window height in cm', + help='window height in cm (default 13)', type=int ) parser.add_argument( @@ -55,7 +55,7 @@ def get_arguments(): dest='width', default=17, action='store', - help='window width in cm', + help='window width in cm (default 17)', type=int ) parser.add_argument( From 2b06ae1f8d8d48dd57a4bda2bf7c7c7cb0a23f63 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sat, 21 Nov 2020 10:51:44 +0100 Subject: [PATCH 24/37] Add counter to slices on pie chart --- misc/scripts/tuptime-plot2.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/misc/scripts/tuptime-plot2.py b/misc/scripts/tuptime-plot2.py index a9df1d72..010799ce 100644 --- a/misc/scripts/tuptime-plot2.py +++ b/misc/scripts/tuptime-plot2.py @@ -166,12 +166,14 @@ def main(): # Set values for each pie plot axs[0].pie([v[1] for v in pie['up']], labels=[k[0].rjust(2, '0') + str('h') for k in pie['up']], - autopct='%1.1f%%', startangle=90, counterclock=False, + autopct=lambda p : '{:.1f}%\n{:,.0f}'.format(p,p * sum([v[1] for v in pie['up']])/100), + startangle=90, counterclock=False, textprops={'fontsize': 8}, wedgeprops={'alpha':0.85}) axs[0].set(aspect="equal", title='Startup') axs[1].pie([v[1] for v in pie['down']], labels=[str(k[0]).rjust(2, '0') + str('h') for k in pie['down']], - autopct='%1.1f%%', startangle=90, counterclock=False, + autopct=lambda p : '{:.1f}%\n{:,.0f}'.format(p,p * sum([v[1] for v in pie['down']])/100), + startangle=90, counterclock=False, textprops={'fontsize': 8}, wedgeprops={'alpha':0.85}) axs[1].set(aspect="equal", title='Shutdown') From cd0e1ce6add5735f9144fb9bff0aacd1aa0d3360 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sat, 21 Nov 2020 10:56:55 +0100 Subject: [PATCH 25/37] Fix typo --- misc/scripts/tuptime-plot1.py | 2 +- misc/scripts/tuptime-plot2.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/misc/scripts/tuptime-plot1.py b/misc/scripts/tuptime-plot1.py index c107f56d..c3fb0210 100644 --- a/misc/scripts/tuptime-plot1.py +++ b/misc/scripts/tuptime-plot1.py @@ -239,7 +239,7 @@ def main(): if arg.report_events: plt.ylabel('Events') - plt.title('Events per state by Day') + plt.title('Events per State by Day') maxv = max(i for v in days.values() for i in v) # Get max value on all ranges plt.yticks(np.arange(0, (maxv + 1), 1)) plt.ylim(top=(maxv + 1)) diff --git a/misc/scripts/tuptime-plot2.py b/misc/scripts/tuptime-plot2.py index 010799ce..d658a129 100644 --- a/misc/scripts/tuptime-plot2.py +++ b/misc/scripts/tuptime-plot2.py @@ -178,7 +178,7 @@ def main(): axs[1].set(aspect="equal", title='Shutdown') axs[0].text(1, -0.1, str('From ' + str(date_limits[0]) + ' to ' + str(date_limits[1])), size=10, ha="center", transform=axs[0].transAxes) - plt.suptitle("Events per hour", fontsize=14) + plt.suptitle("Events per Hour", fontsize=14) else: # Reset date allows position circles inside the same 00..24 range on y-axis From 08dd8215719878f88566cb0c961076a74c38a7b5 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sat, 21 Nov 2020 11:28:52 +0100 Subject: [PATCH 26/37] Year in short form on x-axis --- misc/scripts/tuptime-plot1.py | 2 +- misc/scripts/tuptime-plot2.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/misc/scripts/tuptime-plot1.py b/misc/scripts/tuptime-plot1.py index c3fb0210..efa0ddde 100644 --- a/misc/scripts/tuptime-plot1.py +++ b/misc/scripts/tuptime-plot1.py @@ -120,7 +120,7 @@ def date_range(date_limits): # Convert to epoch dates, pack two of them, begin and end for each split, and create a list with all for reg in range(1, len(dlimit)): ranepo.append([int(dlimit[reg-1].timestamp()), int(dlimit[reg].timestamp())]) - xlegend.append(datetime.fromtimestamp(dlimit[reg-1].timestamp()).strftime('%d-%b-%Y')) + xlegend.append(datetime.fromtimestamp(dlimit[reg-1].timestamp()).strftime('%d-%b-%y')) print('Ranges on list:\t' + str(len(ranepo))) diff --git a/misc/scripts/tuptime-plot2.py b/misc/scripts/tuptime-plot2.py index d658a129..cf15fe17 100644 --- a/misc/scripts/tuptime-plot2.py +++ b/misc/scripts/tuptime-plot2.py @@ -178,7 +178,7 @@ def main(): axs[1].set(aspect="equal", title='Shutdown') axs[0].text(1, -0.1, str('From ' + str(date_limits[0]) + ' to ' + str(date_limits[1])), size=10, ha="center", transform=axs[0].transAxes) - plt.suptitle("Events per Hour", fontsize=14) + plt.suptitle("Events per Hours in all Days", fontsize=14) else: # Reset date allows position circles inside the same 00..24 range on y-axis @@ -206,7 +206,7 @@ def main(): axs = plt.gca() # X as days and defined limits with their margin - axs.xaxis.set_major_formatter(mdates.DateFormatter('%d-%b-%Y')) + axs.xaxis.set_major_formatter(mdates.DateFormatter('%d-%b-%y')) axs.xaxis.set_major_locator(mdates.DayLocator()) plt.xlim(datetime.strptime(date_limits[0], '%d-%b-%Y %H:%M:%S') - timedelta(hours=4), datetime.strptime(date_limits[1], '%d-%b-%Y %H:%M:%S') - timedelta(hours=20)) From 29afb5590ef62bb3e9b1d12e44fe2ba533514f53 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sat, 21 Nov 2020 16:23:29 +0100 Subject: [PATCH 27/37] Add runplot script --- misc/scripts/runplots.sh | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 misc/scripts/runplots.sh diff --git a/misc/scripts/runplots.sh b/misc/scripts/runplots.sh new file mode 100644 index 00000000..93309341 --- /dev/null +++ b/misc/scripts/runplots.sh @@ -0,0 +1,21 @@ +#!/bin/bash + + +# This script executes all the plots available at the same time +# with the same arguments. + +# Python command +PYEX='python3' + +# Days ago +past=30 + +# Size wide and height for nice display on a 16:9 screen +height=10 +wide=22 + +echo "Making plots in backgroud..." +$PYEX ./tuptime-plot1.py -W $wide -H $height -p $past > /dev/null & +$PYEX ./tuptime-plot1.py -W $wide -H $height -p $past -x > /dev/null & +$PYEX ./tuptime-plot2.py -W $wide -H $height -p $past > /dev/null & +$PYEX ./tuptime-plot2.py -W $wide -H $height -p $past -x > /dev/null & From c11feb000fb263cbf3dd77a2d96e40d4bbad10ac Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sat, 21 Nov 2020 17:27:34 +0100 Subject: [PATCH 28/37] Remove range text --- misc/scripts/tuptime-plot2.py | 1 - 1 file changed, 1 deletion(-) diff --git a/misc/scripts/tuptime-plot2.py b/misc/scripts/tuptime-plot2.py index cf15fe17..a586ea9a 100644 --- a/misc/scripts/tuptime-plot2.py +++ b/misc/scripts/tuptime-plot2.py @@ -177,7 +177,6 @@ def main(): textprops={'fontsize': 8}, wedgeprops={'alpha':0.85}) axs[1].set(aspect="equal", title='Shutdown') - axs[0].text(1, -0.1, str('From ' + str(date_limits[0]) + ' to ' + str(date_limits[1])), size=10, ha="center", transform=axs[0].transAxes) plt.suptitle("Events per Hours in all Days", fontsize=14) else: From 78336648bc399a3179eda4c3c92906b58213b444 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sun, 22 Nov 2020 17:01:19 +0100 Subject: [PATCH 29/37] Fix typo --- misc/scripts/tuptime-plot2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/scripts/tuptime-plot2.py b/misc/scripts/tuptime-plot2.py index a586ea9a..1f449d0e 100644 --- a/misc/scripts/tuptime-plot2.py +++ b/misc/scripts/tuptime-plot2.py @@ -177,7 +177,7 @@ def main(): textprops={'fontsize': 8}, wedgeprops={'alpha':0.85}) axs[1].set(aspect="equal", title='Shutdown') - plt.suptitle("Events per Hours in all Days", fontsize=14) + plt.suptitle("Events per Hours in Range", fontsize=14) else: # Reset date allows position circles inside the same 00..24 range on y-axis From 2f1b609a6fad535077090e574e9b10511bf4f253 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sun, 22 Nov 2020 17:01:52 +0100 Subject: [PATCH 30/37] Set auto size based on screen --- misc/scripts/runplots.sh | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/misc/scripts/runplots.sh b/misc/scripts/runplots.sh index 93309341..3432cd84 100644 --- a/misc/scripts/runplots.sh +++ b/misc/scripts/runplots.sh @@ -5,17 +5,32 @@ # with the same arguments. # Python command -PYEX='python3' +PyEx='python3' # Days ago -past=30 +Past=30 -# Size wide and height for nice display on a 16:9 screen -height=10 -wide=22 +# Set wide and height for fit all plots together on the screen +xrandr -v > /dev/null 2>&1 +if [ $? -eq 0 ]; then + Xrdr=`xrandr | grep -i ' connected\( primary\)\?'` # Connected primary monitor + Xmm=`echo $Xrdr | grep -o -P '(?<=\)\ ).*(?=mm\ x\ )'` # X mm size number + Ymm=`echo $Xrdr | grep -o -P '(?<=mm\ x\ ).*(?=mm)'` # Y mm size number + Xcm=`echo "$Xmm / 10 / 2 - 2" | bc` # Half in cm minus boundary + Ycm=`echo "$Ymm / 10 / 2 - 3" | bc` # Half in cm minus boundary +else + echo "### Install 'xrandr' for auto size based on monitor ###" + Xcm=22 + Ycm=10 +fi -echo "Making plots in backgroud..." -$PYEX ./tuptime-plot1.py -W $wide -H $height -p $past > /dev/null & -$PYEX ./tuptime-plot1.py -W $wide -H $height -p $past -x > /dev/null & -$PYEX ./tuptime-plot2.py -W $wide -H $height -p $past > /dev/null & -$PYEX ./tuptime-plot2.py -W $wide -H $height -p $past -x > /dev/null & +echo -e "Days:\t$Past" +echo -e "Wide:\t$Xcm" +echo -e "Height:\t$Ycm" + +echo -e "\nMaking 4 plots in backgroud...\n" +XnY="-W $Xcm -H $Ycm" +$PyEx ./tuptime-plot1.py $XnY -p $Past > /dev/null & +$PyEx ./tuptime-plot1.py $XnY -p $Past -x > /dev/null & +$PyEx ./tuptime-plot2.py $XnY -p $Past > /dev/null & +$PyEx ./tuptime-plot2.py $XnY -p $Past -x From 709d84658a62b98e91777d54f8c267532a61a232 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sun, 22 Nov 2020 19:43:54 +0100 Subject: [PATCH 31/37] Change get arguments --- misc/scripts/runplots.sh | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/misc/scripts/runplots.sh b/misc/scripts/runplots.sh index 3432cd84..54cf8fc5 100644 --- a/misc/scripts/runplots.sh +++ b/misc/scripts/runplots.sh @@ -7,22 +7,25 @@ # Python command PyEx='python3' -# Days ago -Past=30 +# X and Y wide and height for fit all plots together on the screen +if [ -z "$1" ]; then + XargY='22x10' +else + XargY=`grep -oP '\d+x\d+' <<<$1` +fi +Xcm=`cut -dx -f1 <<< $XargY` +Ycm=`cut -dx -f2 <<< $XargY` -# Set wide and height for fit all plots together on the screen -xrandr -v > /dev/null 2>&1 -if [ $? -eq 0 ]; then - Xrdr=`xrandr | grep -i ' connected\( primary\)\?'` # Connected primary monitor - Xmm=`echo $Xrdr | grep -o -P '(?<=\)\ ).*(?=mm\ x\ )'` # X mm size number - Ymm=`echo $Xrdr | grep -o -P '(?<=mm\ x\ ).*(?=mm)'` # Y mm size number - Xcm=`echo "$Xmm / 10 / 2 - 2" | bc` # Half in cm minus boundary - Ycm=`echo "$Ymm / 10 / 2 - 3" | bc` # Half in cm minus boundary +# Days ago +if [ -z "$2" ]; then + Past='30' else - echo "### Install 'xrandr' for auto size based on monitor ###" - Xcm=22 - Ycm=10 + Past=`grep -oP '\d+' <<<$2` fi +echo "Execution: $0 [Width x Height] [Past Days]" +echo "Example: $0 22x10 30" +echo "" +if [ -z "$XargY" ] || [ -z "$Past" ]; then exit; fi echo -e "Days:\t$Past" echo -e "Wide:\t$Xcm" From 77ef4311d5c13594ab8208b8c5a2bbca98503eb9 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Mon, 23 Nov 2020 19:40:58 +0100 Subject: [PATCH 32/37] Better Y description --- misc/scripts/runplots.sh | 27 ++++++++++++++++----------- misc/scripts/tuptime-plot1.py | 4 ++-- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/misc/scripts/runplots.sh b/misc/scripts/runplots.sh index 54cf8fc5..cad37253 100644 --- a/misc/scripts/runplots.sh +++ b/misc/scripts/runplots.sh @@ -22,18 +22,23 @@ if [ -z "$2" ]; then else Past=`grep -oP '\d+' <<<$2` fi -echo "Execution: $0 [Width x Height] [Past Days]" -echo "Example: $0 22x10 30" + +# End Date +if [ -z "$3" ]; then + EndDate='' +else + EndDate="-e `grep -oP '\d+-\w+-\d+' <<<$3`" +fi + +echo "Execution: $0 [Width x Height] [Past Days] [End Date]" +echo "Example: $0 22x10 30 31-Dec-20" echo "" if [ -z "$XargY" ] || [ -z "$Past" ]; then exit; fi -echo -e "Days:\t$Past" -echo -e "Wide:\t$Xcm" -echo -e "Height:\t$Ycm" - -echo -e "\nMaking 4 plots in backgroud...\n" +echo -e "Making 4 plots in backgroud...\n" +echo -e "Wide x Height:\t${Xcm}x${Ycm}" XnY="-W $Xcm -H $Ycm" -$PyEx ./tuptime-plot1.py $XnY -p $Past > /dev/null & -$PyEx ./tuptime-plot1.py $XnY -p $Past -x > /dev/null & -$PyEx ./tuptime-plot2.py $XnY -p $Past > /dev/null & -$PyEx ./tuptime-plot2.py $XnY -p $Past -x +$PyEx ./tuptime-plot1.py $XnY $EndDate -p $Past > /dev/null & +$PyEx ./tuptime-plot1.py $XnY $EndDate -p $Past -x > /dev/null & +$PyEx ./tuptime-plot2.py $XnY $EndDate -p $Past > /dev/null & +$PyEx ./tuptime-plot2.py $XnY $EndDate -p $Past -x diff --git a/misc/scripts/tuptime-plot1.py b/misc/scripts/tuptime-plot1.py index efa0ddde..86c6c8a5 100644 --- a/misc/scripts/tuptime-plot1.py +++ b/misc/scripts/tuptime-plot1.py @@ -238,7 +238,7 @@ def main(): plt.figure(figsize=((arg.width / 2.54), (arg.height / 2.54))) if arg.report_events: - plt.ylabel('Events') + plt.ylabel('Events Counter') plt.title('Events per State by Day') maxv = max(i for v in days.values() for i in v) # Get max value on all ranges plt.yticks(np.arange(0, (maxv + 1), 1)) @@ -257,7 +257,7 @@ def main(): ind = ind + width / 2 else: - plt.ylabel('Hours') + plt.ylabel('Hours Counter') plt.title('Hours per State by Day') plt.yticks(np.arange(0, 25, 2)) plt.ylim(top=26) From 8d99f7cff2ff307a626b0adf362307217f841fdc Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sat, 28 Nov 2020 20:48:52 +0100 Subject: [PATCH 33/37] Normalize spaces and tabs --- README.md | 32 +++--- debian/postinst | 76 +++++++------- debian/postrm | 42 ++++---- misc/scripts/db-tuptime-migrate-2.0-to-3.0.sh | 24 +++-- misc/scripts/db-tuptime-migrate-3.0-to-3.1.sh | 24 +++-- misc/scripts/db-tuptime-migrate-3.1-to-4.0.sh | 22 ++--- misc/scripts/db-tuptime-migrate-4.0-to-5.0.sh | 22 ++--- src/init.d/debian/tuptime | 4 +- src/init.d/redhat/tuptime | 8 +- src/openrc/tuptime | 6 +- src/rc.d/freebsd/tuptime | 2 +- tuptime-install.sh | 45 +++++---- tuptime-manual.txt | 98 +++++++++---------- 13 files changed, 200 insertions(+), 205 deletions(-) diff --git a/README.md b/README.md index ca640ef1..e76d02f4 100644 --- a/README.md +++ b/README.md @@ -8,31 +8,31 @@ Tuptime is a tool for report the historical and statistical real time of the sys Just after install: - System startups: 1 since 21:54:09 24/09/15 - System shutdowns: 0 ok + 0 bad - System life: 21m 30s + System startups: 1 since 21:54:09 24/09/15 + System shutdowns: 0 ok + 0 bad + System life: 21m 30s - System uptime: 100.0% = 21m 30s - System downtime: 0.0% = 0s + System uptime: 100.0% = 21m 30s + System downtime: 0.0% = 0s - Average uptime: 21m 30s - Average downtime: 0s + Average uptime: 21m 30s + Average downtime: 0s - Current uptime: 21m 30s since 21:54:09 24/09/15 + Current uptime: 21m 30s since 21:54:09 24/09/15 A few days later: - System startups: 110 since 10:15:27 08/08/15 - System shutdowns: 107 ok + 2 bad - System life: 47d 12h 2m 15s + System startups: 110 since 10:15:27 08/08/15 + System shutdowns: 107 ok + 2 bad + System life: 47d 12h 2m 15s - System uptime: 4.04% = 1d 22h 4m 44s - System downtime: 95.96% = 45d 13h 57m 30s + System uptime: 4.04% = 1d 22h 4m 44s + System downtime: 95.96% = 45d 13h 57m 30s - Average uptime: 25m 8s - Average downtime: 9h 56m 42s + Average uptime: 25m 8s + Average downtime: 9h 56m 42s - Current uptime: 23m 33s since 21:54:09 24/09/15 + Current uptime: 23m 33s since 21:54:09 24/09/15 Swich to -t | --table option: diff --git a/debian/postinst b/debian/postinst index 29b191a8..805ee9ae 100644 --- a/debian/postinst +++ b/debian/postinst @@ -6,53 +6,53 @@ set -e # summary of how this script can be called: -# * `configure' -# * `abort-upgrade' -# * `abort-remove' `in-favour' -# -# * `abort-remove' -# * `abort-deconfigure' `in-favour' -# `removing' -# +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in - configure) - - # Rename to underscore if previous exists - getent passwd tuptime >/dev/null && usermod -l _tuptime tuptime - getent group tuptime > /dev/null && groupmod -n _tuptime tuptime - - # Create user if not exists - if ! getent passwd _tuptime >/dev/null ; then - echo "Adding _tuptime user..." - adduser --quiet --system --group --disabled-password \ - --home "/var/lib/tuptime" \ - --shell '/usr/sbin/nologin' \ - --gecos 'Tuptime execution user,,,' \ - --force-badname _tuptime - fi - - # Ensure right ownership - if [ -d /var/lib/tuptime ]; then - chown _tuptime:_tuptime /var/lib/tuptime - if [ -f /var/lib/tuptime/tuptime.db ]; then - chown _tuptime:_tuptime /var/lib/tuptime/tuptime.db + configure) + + # Rename to underscore if previous exists + getent passwd tuptime >/dev/null && usermod -l _tuptime tuptime + getent group tuptime > /dev/null && groupmod -n _tuptime tuptime + + # Create user if not exists + if ! getent passwd _tuptime >/dev/null ; then + echo "Adding _tuptime user..." + adduser --quiet --system --group --disabled-password \ + --home "/var/lib/tuptime" \ + --shell '/usr/sbin/nologin' \ + --gecos 'Tuptime execution user,,,' \ + --force-badname _tuptime fi - fi - su -s /bin/sh _tuptime -c "tuptime -x" - ;; + # Ensure right ownership + if [ -d /var/lib/tuptime ]; then + chown _tuptime:_tuptime /var/lib/tuptime + if [ -f /var/lib/tuptime/tuptime.db ]; then + chown _tuptime:_tuptime /var/lib/tuptime/tuptime.db + fi + fi + + su -s /bin/sh _tuptime -c "tuptime -x" + ;; - abort-upgrade|abort-remove|abort-deconfigure) - ;; + abort-upgrade|abort-remove|abort-deconfigure) + ;; - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; esac # dh_installdeb will replace this with shell code automatically diff --git a/debian/postrm b/debian/postrm index 1b2fb81d..966aa731 100644 --- a/debian/postrm +++ b/debian/postrm @@ -6,32 +6,32 @@ set -e # summary of how this script can be called: -# * `remove' -# * `purge' -# * `upgrade' -# * `failed-upgrade' -# * `abort-install' -# * `abort-install' -# * `abort-upgrade' -# * `disappear' -# +# * `remove' +# * `purge' +# * `upgrade' +# * `failed-upgrade' +# * `abort-install' +# * `abort-install' +# * `abort-upgrade' +# * `disappear' +# # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in - purge|disappear) - rm -rf /var/lib/tuptime/ - deluser _tuptime || true - ;; - - remove|upgrade|failed-upgrade|abort-install|abort-upgrade) - ;; - - *) - echo "postrm called with unknown argument \`$1'" >&2 - exit 1 - ;; + purge|disappear) + rm -rf /var/lib/tuptime/ + deluser _tuptime || true + ;; + + remove|upgrade|failed-upgrade|abort-install|abort-upgrade) + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 1 + ;; esac # dh_installdeb will replace this with shell code automatically diff --git a/misc/scripts/db-tuptime-migrate-2.0-to-3.0.sh b/misc/scripts/db-tuptime-migrate-2.0-to-3.0.sh index c89199b4..36d6ea4e 100644 --- a/misc/scripts/db-tuptime-migrate-2.0-to-3.0.sh +++ b/misc/scripts/db-tuptime-migrate-2.0-to-3.0.sh @@ -4,37 +4,37 @@ # This script update the tuptime database format from versions previous 3.0.00 # Change the db origin: -# uptime real, btime integer, shutdown integer +# uptime real, btime integer, shutdown integer # to: -# btime integer, uptime real, offbtime integer, endst integer, downtime real +# btime integer, uptime real, offbtime integer, endst integer, downtime real SOURCE_DB='/var/lib/tuptime/tuptime.db' # Check bash execution if [ ! -n "$BASH" ]; then - echo "--- WARNING - execute only with BASH ---" + echo "--- WARNING - execute only with BASH ---" fi # Test file permissions if [ -w "${SOURCE_DB}" ]; then - echo "Migrating tuptime database format" + echo "Migrating tuptime database format" else - echo "Please, execute this script with a privileged user that can write in: ${SOURCE_DB}" - exit 1 + echo "Please, execute this script with a privileged user that can write in: ${SOURCE_DB}" + exit 1 fi # Test sqlite3 command sqlite3 -version > /dev/null if [ $? -ne 0 ]; then echo "Please, install \"sqlite3\" command for manage sqlite v3 databases" - exit 2 + exit 2 fi # Test bc command bc -version > /dev/null if [ $? -ne 0 ]; then - echo "Please, install \"bc\" command" - exit 2 + echo "Please, install \"bc\" command" + exit 2 fi TMP_DB=$(mktemp) # For temporary process db @@ -45,7 +45,7 @@ cp "${SOURCE_DB}" "${TMP_DB}" sqlite3 "${TMP_DB}" "PRAGMA table_info(tuptime);" | grep -E 'end_state|downtime|offbtime' > /dev/null if [ $? -eq 0 ]; then echo "Database is already in new format" - exit 3 + exit 3 fi # Change shutdown column to end_state @@ -60,14 +60,13 @@ ROWS=$(sqlite3 "${TMP_DB}" "select max(oid) from tuptime;") for I in $(seq 1 "${ROWS}"); do UPTIME=$(sqlite3 "${TMP_DB}" "SELECT uptime from tuptime where oid = ${I};") BTIME=$(sqlite3 "${TMP_DB}" "SELECT btime from tuptime where oid = ${I};") - Z=$((I+1)) + Z=$((I+1)) NEXT_BTIME=$(sqlite3 "${TMP_DB}" "SELECT btime from tuptime where oid = ${Z};") OFFBTIME=$(echo "${UPTIME}" + "${BTIME}" | bc) DOWNBTIME=$(echo "${NEXT_BTIME}" - "${OFFBTIME}" | bc) sqlite3 "${TMP_DB}" "UPDATE tuptime SET downtime = ${DOWNBTIME}, offbtime = ${OFFBTIME} where oid = ${I}" - done # Clear last row shutdown values @@ -94,4 +93,3 @@ rm -f "${TMP_DB}" echo "Backup file in: ${SOURCE_DB}.back" echo "Process completed OK" - diff --git a/misc/scripts/db-tuptime-migrate-3.0-to-3.1.sh b/misc/scripts/db-tuptime-migrate-3.0-to-3.1.sh index 4790b9e6..89bbd2ce 100644 --- a/misc/scripts/db-tuptime-migrate-3.0-to-3.1.sh +++ b/misc/scripts/db-tuptime-migrate-3.0-to-3.1.sh @@ -4,37 +4,37 @@ # This script update the tuptime database format from version 3.0.00 to 3.1.00 # Change the db origin: -# btime integer, uptime real, offbtime integer, endst integer, downtime real +# btime integer, uptime real, offbtime integer, endst integer, downtime real # to: -# btime integer, uptime real, offbtime integer, endst integer, downtime real, kernel text +# btime integer, uptime real, offbtime integer, endst integer, downtime real, kernel text SOURCE_DB='/var/lib/tuptime/tuptime.db' # Check bash execution if [ ! -n "$BASH" ]; then - echo "--- WARNING - execute only with BASH ---" + echo "--- WARNING - execute only with BASH ---" fi # Test file permissions if [ -w "${SOURCE_DB}" ]; then - echo "Migrating tuptime database format" + echo "Migrating tuptime database format" else - echo "Please, execute this script with a privileged user that can write in: ${SOURCE_DB}" - exit 1 + echo "Please, execute this script with a privileged user that can write in: ${SOURCE_DB}" + exit 1 fi # Test sqlite3 command sqlite3 -version > /dev/null if [ $? -ne 0 ]; then echo "Please, install \"sqlite3\" command for manage sqlite v3 databases" - exit 2 + exit 2 fi # Test bc command bc -version > /dev/null if [ $? -ne 0 ]; then - echo "Please, install \"bc\" command" - exit 3 + echo "Please, install \"bc\" command" + exit 3 fi TMP_DB=$(mktemp) # For temporary process db @@ -51,11 +51,10 @@ sqlite3 "${TMP_DB}" "DROP TABLE tuptime_old;" || exit 5 #ROWS=`sqlite3 "${TMP_DB}" "select max(oid) from tuptime;"` # #for I in $(seq 1 ${ROWS}); do -# KERNEL='Linux-3.16.0-4-amd64-x86_64-with-debian-8.0' -# sqlite3 "${TMP_DB}" "UPDATE tuptime SET kernel = \'${KERNEL}\' where oid = ${I}" +# KERNEL='Linux-3.16.0-4-amd64-x86_64-with-debian-8.0' +# sqlite3 "${TMP_DB}" "UPDATE tuptime SET kernel = \'${KERNEL}\' where oid = ${I}" #done - # Backup old db and restore the new mv "${SOURCE_DB}" "${SOURCE_DB}".back && \ mv "${TMP_DB}" "${SOURCE_DB}" && \ @@ -65,4 +64,3 @@ echo "Backup file in: ${SOURCE_DB}.back" rm -f "${TMP_DB}" echo "Process completed OK" - diff --git a/misc/scripts/db-tuptime-migrate-3.1-to-4.0.sh b/misc/scripts/db-tuptime-migrate-3.1-to-4.0.sh index 0eb733a5..bd7da220 100644 --- a/misc/scripts/db-tuptime-migrate-3.1-to-4.0.sh +++ b/misc/scripts/db-tuptime-migrate-3.1-to-4.0.sh @@ -4,14 +4,14 @@ # This script update the tuptime database format from version 3.1.0 or above to to 4.0.0 # # Usage: -# Execute this script. -# It will update the db file on /var/lib/tuptime/tuptime.db -# The original db file will be renamed to /var/lib/tuptime/tuptime.[date].back +# Execute this script. +# It will update the db file on /var/lib/tuptime/tuptime.db +# The original db file will be renamed to /var/lib/tuptime/tuptime.[date].back # # Change the db origin: -# btime integer, uptime real, offbtime integer, endst integer, downtime real, kernel text +# btime integer, uptime real, offbtime integer, endst integer, downtime real, kernel text # to: -# btime integer, uptime real, rntime real, slptime real, offbtime integer, endst integer, downtime real, kernel text +# btime integer, uptime real, rntime real, slptime real, offbtime integer, endst integer, downtime real, kernel text SOURCE_DB='/var/lib/tuptime/tuptime.db' USER_DB=$(stat -c '%U' "${SOURCE_DB}") @@ -20,23 +20,23 @@ BKP_DATE=$(date +%s) # Check bash execution if [ ! -n "$BASH" ]; then - echo "--- WARNING - execute only with BASH ---" + echo "--- WARNING - execute only with BASH ---" fi # Test file permissions if [ -w "${SOURCE_DB}" ]; then - echo -e "\n## Migrating tuptime database format ##\n" - echo "Source file: ${SOURCE_DB}" + echo -e "\n## Migrating tuptime database format ##\n" + echo "Source file: ${SOURCE_DB}" else - echo "Please, execute this script with a privileged user that can write in: ${SOURCE_DB}" - exit 1 + echo "Please, execute this script with a privileged user that can write in: ${SOURCE_DB}" + exit 1 fi # Test sqlite3 command sqlite3 -version > /dev/null if [ $? -ne 0 ]; then echo "Please, install \"sqlite3\" command for manage sqlite v3 databases." - exit 2 + exit 2 fi # Work with a db copy diff --git a/misc/scripts/db-tuptime-migrate-4.0-to-5.0.sh b/misc/scripts/db-tuptime-migrate-4.0-to-5.0.sh index b1ce2962..a51c2025 100644 --- a/misc/scripts/db-tuptime-migrate-4.0-to-5.0.sh +++ b/misc/scripts/db-tuptime-migrate-4.0-to-5.0.sh @@ -4,14 +4,14 @@ # This script update the tuptime database format from version 4.0.0 or above to to 5.0.0 # # Usage: -# Execute this script. -# It will update the db file on /var/lib/tuptime/tuptime.db -# The original db file will be renamed to /var/lib/tuptime/tuptime.[date].back +# Execute this script. +# It will update the db file on /var/lib/tuptime/tuptime.db +# The original db file will be renamed to /var/lib/tuptime/tuptime.[date].back # # Change the db origin: -# btime integer, uptime real, rntime real, slptime real, offbtime integer, endst integer, downtime real, kernel text +# btime integer, uptime real, rntime real, slptime real, offbtime integer, endst integer, downtime real, kernel text # to: -# bootid text, btime integer, uptime real, rntime real, slptime real, offbtime integer, endst integer, downtime real, kernel text +# bootid text, btime integer, uptime real, rntime real, slptime real, offbtime integer, endst integer, downtime real, kernel text SOURCE_DB='/var/lib/tuptime/tuptime.db' USER_DB=$(stat -c '%U' "${SOURCE_DB}") @@ -21,23 +21,23 @@ BKP_DATE=$(date +%s) # Check bash execution if [ ! -n "$BASH" ]; then - echo "--- WARNING - execute only with BASH ---" + echo "--- WARNING - execute only with BASH ---" fi # Test file permissions if [ -w "${SOURCE_DB}" ]; then - echo -e "\n## Migrating tuptime database format ##\n" - echo "Source file: ${SOURCE_DB}" + echo -e "\n## Migrating tuptime database format ##\n" + echo "Source file: ${SOURCE_DB}" else - echo "Please, execute this script with a privileged user that can write in: ${SOURCE_DB}" - exit 1 + echo "Please, execute this script with a privileged user that can write in: ${SOURCE_DB}" + exit 1 fi # Test sqlite3 command sqlite3 -version > /dev/null if [ $? -ne 0 ]; then echo "Please, install \"sqlite3\" command for manage sqlite v3 databases." - exit 2 + exit 2 fi # Work with a db copy diff --git a/src/init.d/debian/tuptime b/src/init.d/debian/tuptime index 7a606ec2..eb977828 100755 --- a/src/init.d/debian/tuptime +++ b/src/init.d/debian/tuptime @@ -50,8 +50,8 @@ do_stop () { } do_status () { - # Status service - su -s /bin/sh $USER -c "$PATH_BIN" + # Status service + su -s /bin/sh $USER -c "$PATH_BIN" } diff --git a/src/init.d/redhat/tuptime b/src/init.d/redhat/tuptime index 8aa630e5..68e203ed 100755 --- a/src/init.d/redhat/tuptime +++ b/src/init.d/redhat/tuptime @@ -27,7 +27,7 @@ RETVAL=0 do_start () { # Start service echo -n $"Starting tuptime: " - daemon --user $USER $PATH_BIN -x + daemon --user $USER $PATH_BIN -x RETVAL=$? echo [ $RETVAL -eq 0 ] && touch ${LOCKFILE} @@ -37,11 +37,11 @@ do_start () { do_stop () { # Stop service echo -n $"Stopping tuptime: " - daemon --user $USER $PATH_BIN -xg - $PATH_BIN -xg + daemon --user $USER $PATH_BIN -xg + $PATH_BIN -xg RETVAL=$? echo - [ $RETVAL -eq 0 ] && rm -f ${LOCKFILE} + [ $RETVAL -eq 0 ] && rm -f ${LOCKFILE} return $RETVAL } diff --git a/src/openrc/tuptime b/src/openrc/tuptime index a486ff0d..d6ac8bed 100644 --- a/src/openrc/tuptime +++ b/src/openrc/tuptime @@ -6,9 +6,9 @@ command_user='_tuptime' command_args='-x' depend() { - need localmount - after bootmisc - after clock + need localmount + after bootmisc + after clock } start() { diff --git a/src/rc.d/freebsd/tuptime b/src/rc.d/freebsd/tuptime index 23eb2680..a757460a 100755 --- a/src/rc.d/freebsd/tuptime +++ b/src/rc.d/freebsd/tuptime @@ -19,7 +19,7 @@ tuptime_start() { echo "Starting $name." command_args="-x" - + su -m ${tuptime_user} -c "$name $command_args" 2> /dev/null || $name $command_args 2> /dev/null } diff --git a/tuptime-install.sh b/tuptime-install.sh index d8f4f978..13be8c4f 100644 --- a/tuptime-install.sh +++ b/tuptime-install.sh @@ -5,8 +5,8 @@ # v.1.8.8 # # Usage: -# bash tuptime-install.sh Normal installation -# bash tuptime-install.sh -d Installation using dev branch +# bash tuptime-install.sh Default master install +# bash tuptime-install.sh -d Install using dev branch # # Execution user @@ -24,22 +24,21 @@ DEV=0 # Check bash execution if [ ! -n "$BASH" ]; then - echo "--- WARNING - execute only with BASH ---" + echo "--- WARNING - execute only with BASH ---" fi # Check root execution if [ "$(id -u)" != "0" ]; then - echo "Please run this script as root" - exit + echo "Please run this script as root" + exit fi # Test arguments while test $# -gt 0; do - case "$1" in - -d) DEV=1 - ;; - esac - shift + case "$1" in + -d) DEV=1 ;; + esac + shift done # Test if it is a linux system @@ -65,22 +64,22 @@ fi # Test if python is installed pyver=$(python3 --version 2> /dev/null) if [ $? -ne 0 ]; then - echo "ERROR: Python not available" - echo "Please, install version 3 or greater"; exit 1 + echo "ERROR: Python not available" + echo "Please, install version 3 or greater"; exit 1 else # Test if version 3 or avobe of python is installed pynum=$(echo "${pyver}" | tr -d '.''' | grep -Eo '[0-9]*' | head -1 | cut -c 1-2) - if [ "$pynum" -lt 30 ] ; then - echo "ERROR: Its needed Python version 3, not ${pyver}" - echo "Please, upgrade it."; exit 1 - else + if [ "$pynum" -lt 30 ] ; then + echo "ERROR: Its needed Python version 3, not ${pyver}" + echo "Please, upgrade it."; exit 1 + else # Test if all modules needed are available pymod=$(python3 -c "import sys, os, argparse, locale, platform, signal, logging, sqlite3, datetime") - if [ $? -ne 0 ]; then - echo "ERROR: Please, ensure that these Python modules are available in the local system:" - echo "sys, os, optparse, sqlite3, locale, platform, datetime, logging"; exit 1 - fi - fi + if [ $? -ne 0 ]; then + echo "ERROR: Please, ensure that these Python modules are available in the local system:" + echo "sys, os, optparse, sqlite3, locale, platform, datetime, logging"; exit 1 + fi + fi fi # Set SystemD path @@ -108,7 +107,7 @@ echo "" echo "+ Getting source tar file" if [ ${DEV} -eq 1 ]; then - echo " ...using dev branch" + echo " ...using dev branch" tar xz --strip 1 -C "${F_TMP1}" -f <(curl -sL https://github.com/rfrail3/tuptime/archive/dev.tar.gz) || exit else tar xz --strip 1 -C "${F_TMP1}" -f <(curl -sL https://github.com/rfrail3/tuptime/archive/master.tar.gz) || exit @@ -124,7 +123,7 @@ echo "+ Creating Tuptime execution user '_tuptime'" useradd -h > /dev/null 2>&1 if [ $? -eq 0 ]; then useradd --system --no-create-home --home-dir '/var/lib/tuptime' \ - --shell '/bin/false' --comment 'Tuptime execution user' "${EXUSR}" + --shell '/bin/false' --comment 'Tuptime execution user' "${EXUSR}" else adduser -S -H -h '/var/lib/tuptime' -s '/bin/false' "${EXUSR}" fi diff --git a/tuptime-manual.txt b/tuptime-manual.txt index e388cb5e..7f927a27 100644 --- a/tuptime-manual.txt +++ b/tuptime-manual.txt @@ -93,7 +93,7 @@ For Linux systems: # install -m 644 tuptime/src/cron.d/tuptime /etc/cron.d/tuptime If it use systemd, copy service file and enable it: - + # install -m 644 tuptime/src/systemd/tuptime.service /lib/systemd/system/tuptime.service # systemctl enable tuptime.service && systemctl start tuptime.service @@ -112,7 +112,7 @@ For Linux systems: # install -m 755 tuptime/src/init.d/debian/tuptime /etc/init.d/tuptime # update-rc.d tuptime defaults - # /etc/init.d/tuptime start + # /etc/init.d/tuptime start That's all, enjoy it. @@ -228,36 +228,36 @@ These are the command line options, no configuration file is used: Change the datetime/timestamp format. By default the output use the configured system locales. Allow values are: - %a Weekday as locale’s abbreviated name. - %A Weekday as locale’s full name. - %w Weekday as a decimal number, where 0 is Sunday and 6 is - Saturday. - %d Day of the month as a zero-padded decimal number. - %b Month as locale’s abbreviated name. - %B Month as locale’s full name. - %m Month as a zero-padded decimal number. - %y Year without century as a zero-padded decimal number. - %Y Year with century as a decimal number. - %H Hour (24-hour clock) as a zero-padded decimal number. - %I Hour (12-hour clock) as a zero-padded decimal number. - %p Locale’s equivalent of either AM or PM. - %M Minute as a zero-padded decimal number. - %S Second as a zero-padded decimal number. - %f Microsecond as a decimal number, zero-padded on the left. - %z UTC offset in the form +HHMM or -HHMM (empty string if the - the object is naive). - %Z Time zone name (empty string if the object is naive). - %j Day of the year as a zero-padded decimal number. - %U Week number of the year (Sunday as the first day of the week) - as a zero padded decimal number. All days in a new year - preceding the first Sunday are considered to be in week 0. - %W Week number of the year (Monday as the first day of the week) - as a decimal number. All days in a new year preceding the - first Monday are considered to be in week 0. - %c Locale’s appropriate date and time representation. - %x Locale’s appropriate date representation. - %X Locale’s appropriate time representation. - %% A literal '%' character. + %a Weekday as locale’s abbreviated name. + %A Weekday as locale’s full name. + %w Weekday as a decimal number, where 0 is Sunday and 6 is + Saturday. + %d Day of the month as a zero-padded decimal number. + %b Month as locale’s abbreviated name. + %B Month as locale’s full name. + %m Month as a zero-padded decimal number. + %y Year without century as a zero-padded decimal number. + %Y Year with century as a decimal number. + %H Hour (24-hour clock) as a zero-padded decimal number. + %I Hour (12-hour clock) as a zero-padded decimal number. + %p Locale’s equivalent of either AM or PM. + %M Minute as a zero-padded decimal number. + %S Second as a zero-padded decimal number. + %f Microsecond as a decimal number, zero-padded on the left. + %z UTC offset in the form +HHMM or -HHMM (empty string if the + the object is naive). + %Z Time zone name (empty string if the object is naive). + %j Day of the year as a zero-padded decimal number. + %U Week number of the year (Sunday as the first day of the week) + as a zero padded decimal number. All days in a new year + preceding the first Sunday are considered to be in week 0. + %W Week number of the year (Monday as the first day of the week) + as a decimal number. All days in a new year preceding the + first Monday are considered to be in week 0. + %c Locale’s appropriate date and time representation. + %x Locale’s appropriate date representation. + %X Locale’s appropriate time representation. + %% A literal '%' character. Examples: @@ -509,7 +509,7 @@ that value if your requirements are narrow. | Default output | ================== -System startups: +System startups: Total number of system startups registered since first timestamp available. System shutdowns: @@ -691,28 +691,28 @@ The options --tsince, --tuntil and --tat use epoch timestamp format, as quick reference here are some notes: Seconds equivalences: - 1 year 31536000 seconds - 1 month 2592000 seconds - 1 week 604800 seconds - 1 day 86400 seconds - 1 hour 3600 seconds + 1 year 31536000 seconds + 1 month 2592000 seconds + 1 week 604800 seconds + 1 day 86400 seconds + 1 hour 3600 seconds Convert human datetime to epoch: - date --date="JAN-18-2018" +%s - date --date="20-JAN-18" +%s - date --date="2018-01-20 16:21:42" +%s - date --date="2018-01-20 16:21:42 GMT+2" +%s - date --date="3 week ago" +%s - date --date="1 year ago" +%s - date --date="now" +%s + date --date="JAN-18-2018" +%s + date --date="20-JAN-18" +%s + date --date="2018-01-20 16:21:42" +%s + date --date="2018-01-20 16:21:42 GMT+2" +%s + date --date="3 week ago" +%s + date --date="1 year ago" +%s + date --date="now" +%s Convert epoch to human datetime: - date --date="@1516748400" + date --date="@1516748400" More info about datetime input formats: - man date - 'https://www.gnu.org/software/coreutils/manual/html_node/ - Date-input-formats.html#Date-input-formats' + man date + 'https://www.gnu.org/software/coreutils/manual/html_node/ + Date-input-formats.html#Date-input-formats' From 0f1578ae430fc46bf7ba1d66c254b2df31f42fb9 Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sat, 28 Nov 2020 21:05:58 +0100 Subject: [PATCH 34/37] Bump version --- CHANGELOG | 7 +++++++ debian/changelog | 7 +++++++ misc/rpm/rpm-readme.txt | 6 +++--- misc/rpm/tuptime.spec | 4 ++-- tuptime-manual.txt | 2 +- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4e9d1c9f..28e9c9ec 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,10 @@ +tuptime (5.0.2) unstable; urgency=low + + * Option --decp usable but deprecated + * Using subprocess module on BSDs + + -- Ricardo Fraile Sat, 28 Nov 2020 20:54:00 +0100 + tuptime (5.0.1) unstable; urgency=low * Identify new startups with boot_id on FreeBSD diff --git a/debian/changelog b/debian/changelog index 04cbcb8b..b60d20d1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +tuptime (5.0.2) unstable; urgency=low + + * Option --decp usable but deprecated + * Using subprocess module on BSDs + + -- Ricardo Fraile Sat, 28 Nov 2020 20:54:00 +0100 + tuptime (5.0.1) unstable; urgency=low * Identify new startups with boot_id on FreeBSD diff --git a/misc/rpm/rpm-readme.txt b/misc/rpm/rpm-readme.txt index 467f5b7d..7c18c126 100644 --- a/misc/rpm/rpm-readme.txt +++ b/misc/rpm/rpm-readme.txt @@ -40,9 +40,9 @@ Z.- For testing with "dev" branch. Install "git" on step "1" and replace step "2" with the following: cd ~ - git clone -b dev --depth=1 https://github.com/rfrail3/tuptime.git tuptime-5.0.1 + git clone -b dev --depth=1 https://github.com/rfrail3/tuptime.git tuptime-5.0.2 rpmdev-setuptree cd ~/rpmbuild/SPECS/ - cp ../../tuptime-5.0.1/misc/rpm/tuptime.spec . - tar -czvf ../SOURCES/5.0.1.tar.gz ../../tuptime-5.0.1 + cp ../../tuptime-5.0.2/misc/rpm/tuptime.spec . + tar -czvf ../SOURCES/5.0.2.tar.gz ../../tuptime-5.0.2 rpmbuild -ba --target=noarch tuptime.spec diff --git a/misc/rpm/tuptime.spec b/misc/rpm/tuptime.spec index 7e40e4b0..2610e765 100644 --- a/misc/rpm/tuptime.spec +++ b/misc/rpm/tuptime.spec @@ -1,5 +1,5 @@ Name: tuptime -Version: 5.0.1 +Version: 5.0.2 Release: 1%{?dist} Summary: Report historical system real time @@ -90,5 +90,5 @@ su -s /bin/sh _tuptime -c "(umask 0022 && /usr/bin/tuptime -x)" %changelog -* Sat Oct 31 2020 Ricardo Fraile 5.0.1-1 +* Sat Oct 31 2020 Ricardo Fraile 5.0.2-1 - RPM release diff --git a/tuptime-manual.txt b/tuptime-manual.txt index 7f927a27..b9803888 100644 --- a/tuptime-manual.txt +++ b/tuptime-manual.txt @@ -3,7 +3,7 @@ ---------------------- version 5.0.2 Ricardo F. - 12/Nov/2020 + 28/Nov/2020 From 136a48a64e64e0a716ce9b146e6d51182e21bd5b Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sat, 28 Nov 2020 21:33:46 +0100 Subject: [PATCH 35/37] Use short form in date example call --- tuptime-manual.txt | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/tuptime-manual.txt b/tuptime-manual.txt index b9803888..c549c493 100644 --- a/tuptime-manual.txt +++ b/tuptime-manual.txt @@ -404,7 +404,7 @@ These are the command line options, no configuration file is used: Examples: tuptime --tat 1555280149 - tuptime --tat `date --date="1 day ago" +%s` + tuptime --tat `date -d "1 day ago" +%s` tuptime -cs --tat 1555281311 @@ -414,7 +414,7 @@ These are the command line options, no configuration file is used: Examples: tuptime --tsince 1454998872 - tuptime --tsince `date --date="20-JAN-18" +%s` + tuptime --tsince `date -d "20-JAN-18" +%s` tuptime --tsince -31536000 # Since one year ago @@ -424,7 +424,7 @@ These are the command line options, no configuration file is used: Examples: tuptime --tuntil 1454999619 - tuptime --tuntil `date --date="2018-01-20 16:21:42" +%s` + tuptime --tuntil `date -d "2018-01-20 16:21:42" +%s` tuptime --tuntil -2592000 # Until one month ago @@ -698,16 +698,19 @@ Seconds equivalences: 1 hour 3600 seconds Convert human datetime to epoch: - date --date="JAN-18-2018" +%s - date --date="20-JAN-18" +%s - date --date="2018-01-20 16:21:42" +%s - date --date="2018-01-20 16:21:42 GMT+2" +%s - date --date="3 week ago" +%s - date --date="1 year ago" +%s - date --date="now" +%s + date -d "JAN-18-2018" +%s + date -d "20-JAN-18" +%s + date -d "2018-01-20 16:21:42" +%s + date -d "2018-01-20 16:21:42 GMT+2" +%s + date -d "3 week ago" +%s + date -d "1 year ago" +%s + date -d "now" +%s Convert epoch to human datetime: - date --date="@1516748400" + date -d "@1516748400" + +Preceding conversions uses GNU date, on FreeBSD install "coreutils" and call +them with "gdate". More info about datetime input formats: man date From 984f1173cea9eb2296ce63ea9f397c6d6b377e5e Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Tue, 22 Dec 2020 13:50:34 +0100 Subject: [PATCH 36/37] Update doc --- tuptime-manual.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tuptime-manual.txt b/tuptime-manual.txt index c549c493..ba51ea99 100644 --- a/tuptime-manual.txt +++ b/tuptime-manual.txt @@ -626,8 +626,10 @@ with high load or with high disk I/O, wrong computation of jiffies / HZ and the problema of lost ticks. A slightly drift is compensate over the uptime value, but a very high drift can cause -inconsistent registers and output, for example, Raspberry Pi don't have any clock and -initializes from 1 January 1970. +abnormal registers and output, for example, Raspberry Pi don't have any clock and +initializes from 1 January 1970. A downtime of 0, when it's clear than it was +physically impossible, it's a common indicator than the clock had a large backward +sync jump. As Tuptime have time dependency, their Systemd service unit pulls time-sync.target and it's ordered before it. Note that it doesn't assure that the clock is syncronized, From 18f9538a68dbea7fa4480f1b72a9e6505951639c Mon Sep 17 00:00:00 2001 From: Ricardo F Date: Sat, 2 Jan 2021 15:58:15 +0100 Subject: [PATCH 37/37] Bump version --- CHANGELOG | 2 +- debian/changelog | 2 +- misc/rpm/tuptime.spec | 2 +- src/man/tuptime.1 | 2 +- src/tuptime | 2 +- tuptime-manual.txt | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 28e9c9ec..90164c4c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,7 +3,7 @@ tuptime (5.0.2) unstable; urgency=low * Option --decp usable but deprecated * Using subprocess module on BSDs - -- Ricardo Fraile Sat, 28 Nov 2020 20:54:00 +0100 + -- Ricardo Fraile Sat, 02 Jan 2021 09:01:00 +0100 tuptime (5.0.1) unstable; urgency=low diff --git a/debian/changelog b/debian/changelog index b60d20d1..30b1bb80 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,7 +3,7 @@ tuptime (5.0.2) unstable; urgency=low * Option --decp usable but deprecated * Using subprocess module on BSDs - -- Ricardo Fraile Sat, 28 Nov 2020 20:54:00 +0100 + -- Ricardo Fraile Sat, 02 Jan 2021 09:01:00 +0100 tuptime (5.0.1) unstable; urgency=low diff --git a/misc/rpm/tuptime.spec b/misc/rpm/tuptime.spec index 2610e765..caf62fa8 100644 --- a/misc/rpm/tuptime.spec +++ b/misc/rpm/tuptime.spec @@ -90,5 +90,5 @@ su -s /bin/sh _tuptime -c "(umask 0022 && /usr/bin/tuptime -x)" %changelog -* Sat Oct 31 2020 Ricardo Fraile 5.0.2-1 +* Sat Jan 02 2021 Ricardo Fraile 5.0.2-1 - RPM release diff --git a/src/man/tuptime.1 b/src/man/tuptime.1 index 75f3220d..935aeefc 100644 --- a/src/man/tuptime.1 +++ b/src/man/tuptime.1 @@ -234,7 +234,7 @@ Ricardo Fraile .SH "COPYRIGHT" .PP -Copyright (C) 2020 by Ricardo F. All Rights Reserved. +Copyright (C) 2021 by Ricardo F. All Rights Reserved. This product is distributed in the hope that it will be useful, but WITHOUT any warranty; without even the implied warranty of diff --git a/src/tuptime b/src/tuptime index 269ccc35..87b189d1 100644 --- a/src/tuptime +++ b/src/tuptime @@ -3,7 +3,7 @@ """tuptime - Report the historical and statistical real time of the system, keeping it between restarts""" -# Copyright (C) 2011-2020 - Ricardo F. +# Copyright (C) 2011-2021 - Ricardo F. # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/tuptime-manual.txt b/tuptime-manual.txt index ba51ea99..a40bf762 100644 --- a/tuptime-manual.txt +++ b/tuptime-manual.txt @@ -3,7 +3,7 @@ ---------------------- version 5.0.2 Ricardo F. - 28/Nov/2020 + 02/Jan/2021