Skip to content

Instantly share code, notes, and snippets.

@afair
Last active October 18, 2021 21:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save afair/0112bde4c59d3c460ac9f6a0af86dcd1 to your computer and use it in GitHub Desktop.
Save afair/0112bde4c59d3c460ac9f6a0af86dcd1 to your computer and use it in GitHub Desktop.
Takes (log) lines with ISO timestamp at start, counts by year/month/day/hour/minute(default)/second. Useful for log analysis counts, like "uniq -c" for time periods.
#!/usr/bin/env perl
################################################################################
# time-count : Counts log lines per time (number of chars of timestamp)`
# Takes (log) lines with timestamp near the start, looking for:
# * ISO/ISO-8601 : yyyy-mm-dd.hh:mm:ss
# * Common Log Format: [dd/mmm/yyyy:hh:mm:ss -zzzz]
# * Unix epoch : 1521458735.901159500
# counts by year/month/day/hour/minute(default)/second.
# Useful for log analysis counts, like "uniq -c" for time periods.
# Intended for use as a Unix command taking its input as a pipe.
#
#-------------------------------------------------------------------------------
# Usage : time-count [year|month|day|hour|MINUTE|second]
# Example: grep xxx yy.log | ... | time-count hour
# Input : lines containing ISO Timestamp, Common Log Format, or Epoch Times
# Output : 2019-07-31T16 502
# Environment: TIMECOUNT_UTC=1 indicates Epoch times are formatted
# as UTC instead of Local Time.
#
#-------------------------------------------------------------------------------
# Author: Allen Fair ($first.$last@gmail.com @allenfair)
# MIT License: See https://opensource.org/licenses/MIT
#
# Copyright (c) 2019 Allen Fair
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
# Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
################################################################################
use strict;
my %units = (year=>4, month=>7, day=>10, hour=>13, minute=>16, second=>19);
my %months= (Jan=>'01', Feb=>'02', Mar=>'03', Apr=>'04', May=>'05', Jun=>'06',
Jul=>'07', Aug=>'08', Sep=>'09', Oct=>'10', Nov=>'11', Dec=>'12');
my ($u) = @ARGV;
my $part = $units{lc $u} || $units{minute};
my $c = 0;
my $tm = '';
my $utc = $ENV{TIMECOUNT_UTC} ? 1 : 0;
while (my $rec = <STDIN>) {
if ($rec =~ /^.*?(\d{4}-\d{2}-\d{2}.[\d:]+)/) {
$rec = $1;
} elsif ($rec =~ m|^.*?(\d{2})/(\w{3})/(\d{4}):(\d{2}:\d{2}:\d{2})|) { # [31/Jul/2019:16:49:52 -0400]
$rec = "$3-$months{$2}-$1T$4";
} elsif ($rec =~ /^.*?(\d{7,10})/) { # Epoch
my ($ss, $mm, $hh, $dd, $mo, $yy, $ww, $jj, $dst) =
$utc ? gmtime($1) : localtime($1);
$rec = sprintf "%04d-%02d-%02dT%02d:%02d:%02d", $yy+1900, $mo+1, $dd, $hh, $mm, $ss;
} else {
next; # No time in the record, so skip.
}
my $ts = substr($rec,0,$part);
if ($ts gt $tm) {
print "$tm\t$c\n" if $tm gt ' ';
$c = 0;
$tm = $ts;
}
++$c;
}
print "$tm\t$c\n" if $c > 0;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment