#!/usr/bin/env python
#
# Copyright (c) 2005, Egor Starostin
#
# 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.
#

"""
Trace Session Data

When your Oracle server works in MTS (multithreaded server) configuration
then trace data from a single session may be scattered through several
trace files.

This small utility allows you to recompose trace data in one file.
"""

__revision__ = "$Id: trcsess.py,v 1.2 2005/02/21 06:43:44 egor_starostin Exp $"
__version__  = __revision__.split()[2]

import sys,re,getopt,os,time
try:
  import psyco; psyco.full()
except ImportError:
  pass

def displayHelp(msg):
  if msg:
    print msg
  print """usage: trcsess.py [-h|--help] -s sid.serial|--sessionid=sid.serial [-o outfile|--output=outfile] <trace_file_names>
  --help             print this screen
  --sessionid        specify sid.serial# 
                       (without spaces and delimited by dot; as in trace file)
  --output           specify output file; if not specified then print to stdout
  <trace_file_names> space separated list of trace files
  """

sessionId = ''; outFile = ''
try:
  opts,args = getopt.getopt(sys.argv[1:],'f:d:hs:o:',
                            ['file=','directory=','help','sessionid=','output='])
except getopt.error, msg:
  displayHelp(msg)
  sys.exit(1)
for opt,val in opts:
  if opt in ('-h','--help'):      displayHelp("Trace Session Data v%s (c) 2005, Egor Starostin" % __version__); sys.exit(0)
  if opt in ('-s','--sessionid'): sessionId = val
  if opt in ('-o','--output'):    outFile = val
if args:
  trcFiles = args
else:
  displayHelp("error: you need to specify <trace_file_names>")
  sys.exit(1)

if not sessionId:
  displayHelp('error: you need to specify sessionid')
  sys.exit(1)

if outFile:
  out = open(outFile,'w')
else:
  out = sys.stdout

sidPattern = '*** SESSION ID:(%s) ' % sessionId
sidPatternLen = len(sidPattern)
Pieces = []
for f in trcFiles:
  startLine = -1; endLine = -1; i = 0; insid = False
  for l in file(f):
    i += 1
    if l[:16] == '*** SESSION ID:(':
      if l[:sidPatternLen] == sidPattern:
        if insid:
	  endLine = i - 1
          Pieces.append((f,datetime,startLine,endLine))
        datetime = l[sidPatternLen:-1]
        startLine = i
        insid = True
      else:
        if insid:
          endLine = i - 1
          Pieces.append((f,datetime,startLine,endLine))
          insid = False
  if insid:
    endLine = i
    Pieces.append((f,datetime,startLine,endLine))
    insid = False

Pieces.sort(lambda a,b:cmp(a[1],b[1]))

#let's join similar pieces.
# i.e. (f1,d1,1,10),(f1,d2,11,20) joins to (f1,d1,1,20)
Pieces2 = []
outf = ''; outdt = ''; outs = 0; oute = 0
for el in Pieces:
  if outf == el[0] and oute == el[2]-1:
    oute = el[3]
  else:
    if outf != '':
      Pieces2.append((outf,outdt,outs,oute))
    (outf,outdt,outs,oute) = el
if outf != '':    
  Pieces2.append((outf,outdt,outs,oute))

# now print our pieces sorted by time
for el in Pieces2:
  (f,dt,s,e) = el
  i = 0
  for l in file(f):
    i += 1
    if i < s:
      continue
    elif i > e:
      break
    else:
      out.write(l)
