#!/usr/bin/env python3
# Copyright (c) 2012 Arista Networks, Inc.  All rights reserved.
# Arista Networks, Inc. Confidential and Proprietary.

import errno
import optparse # pylint: disable=deprecated-module
import sys
import time
import EosLogUtil

usage = r"""

   %prog -- Dumps EOS log files

   %prog COMMAND -l|--logdir LOGDIR [-f|--file SAVEFILE] [-m|--match REGEX]
                 [-r|--runId RUNID] [-z|--maxsize MAXSIZE] [-n|--no-header]

   COMMAND:

   save: Save the current logfile information to stdout.

   dump: Dump the current logfile content. If a valid savefile is specified,
         it only dumps new content since the save, and updates the savefile
         with the new information.

   REGEX is a regular expression that is used to retrieve filenames
   that can be grouped together. The matched string is used as the name of
   the logfile, or you can use '?P<name>' to specify the name. For example,
   if there are the following files:

      eos, eos.1.gz, eos-console, eos-console.1.gz

   using "-m eos" would generate two files:

      eos (eos and eos.1.gz)
      eos-console (contains eos-console and eos-console1.gz)

   If you want to only match eos and eos.1.gz under one file 'eos', you can do

      -m '(?P<name>eos)($|\..*\.gz)'

   Alternatively you can also use lookahead:

      -m 'eos(?=($|\..*\.gz))'
"""

op = optparse.OptionParser( prog='FetchLogs', usage=usage )
op.add_option( '-l', '--logdir', action='store', help='log directory' )
op.add_option( '-f', '--file', action='store', help='save file' )
op.add_option( '-m', '--match', action='store',
               help='regex for matching names' )
op.add_option( '-r', '--runId', action='store', help='Record runId' )
op.add_option( '-z', '--maxsize', action='store', type=int,
               help='Max dump size for any file' )
op.add_option( '-n', '--no-header', action='store_true',
               help='Do not print header' )
op.add_option( '-o', '--out', action='store',
               help='outptut filename' )
op.add_option( '--preserve-crashdumps', action='store_true',
               help='exceed maxsize to help preserve crash logs' )

opts, args = op.parse_args( )

if not args or len( args ) > 1:
   op.error( "Missing or extra command" )
if not opts.logdir:
   op.error( "Missing log directory" )
if opts.out:
   # pylint: disable=consider-using-with
   out = open( opts.out, "wt" )
else:
   out = sys.stdout
if opts.preserve_crashdumps:
   crashBracket = ( b"---------- BEGIN MANTLE DUMP", b"END MANTLE DUMP ----------" )
else:
   crashBracket = None

try:
   if args[ 0 ] == 'save':
      EosLogUtil.save( opts.logdir, opts.file, match=opts.match )
   elif args[ 0 ] == 'dump':
      files = EosLogUtil.dump( opts.logdir, opts.file,
                               match=opts.match, runId=opts.runId )
      # output by filename
      for name in sorted( files ):
         vfile = files[ name ]
         if not opts.no_header:
            mtime = time.localtime( vfile.mtime() )
            cursor = vfile.tell()
            header = [ '-' * 15, time.strftime( "%b %d %H:%M", mtime ), name ]
            if cursor:
               lastFetched = ""
               if cursor.runId:
                  # pylint: disable-next=consider-using-f-string
                  lastFetched = ", last fetched by run %s" % cursor.runId
               # pylint: disable-next=consider-using-f-string
               header.append( '[offset %d:%d%s]' % ( len( cursor.inodes ) - 1,
                                                     cursor.currentFileSize,
                                                     lastFetched ) )
            header.append( '-' * 15 )
            out.write( ' '.join( header ) )
            out.write( '\n' )
            out.flush()
         if opts.maxsize:
            out.buffer.write( vfile.readTail( opts.maxsize,
                                              opts.maxsize * 4, crashBracket ) )
            out.write( '\n' )
            out.flush()
         else:
            for x in vfile:
               out.buffer.write( x )
            if not opts.no_header:
               # print an empty line only when it's no_header
               out.write( '\n' )
   else:
      op.error( "Invalid command" )
except KeyboardInterrupt:
   pass
except OSError as e:
   if e.errno == errno.EPIPE:
      sys.exit()
   raise
