#!/usr/bin/env python
"""
Write a NetLogger-formatted message to stdout.
"""
__author__ = "Dan Gunter <dkgunter@lbl.gov>"
__rcsid__ = "$Id: nl_write 788 2008-06-02 17:11:49Z dang $"

import logging
import optparse
import socket
import sys
import syslog
import time
from netlogger import nllog
from netlogger import nlapi
from netlogger import util
from netlogger.nlapi import Level

# Logging
log = nllog.NullLogger()
def activateLogging(name="netlogger.nl_tbl"):
    global log
    log = nllog.getScriptLogger(name)

# some defaults
_P = { 'event' : 'nlwrite.event',
       'level' : Level.INFO,
       'udp_port' : 514,
       'tcp_port' : 14380,
}

def parseNVP(args, option_parser):
    d = { }
    for arg in args:
        try:
            name, value = arg.split('=')
        except ValueError:
            option_parser.error("argument '%s' not in form name=value" % arg)
        d[name] = value
    return d

def syslogHeader(host, program="cedps-logger"):
    """Return string to be used as a message header for syslogging it
    """
    # build syslog 'priority'
    pri =   "<%d>" % (syslog.LOG_USER + syslog.LOG_INFO)
    # build syslog formatted date
    localtime = time.localtime()
    day = time.strftime("%d", localtime)
    if day[0] == "0":
        day = " " + day[1:]  # syslog RFC says this MUST be a space
    val = time.strftime("%b %%s %H:%M:%S", localtime)
    date = val % day 
    return "%s%s %s %s: " % (pri, date, host, program)
	
def main():
    usage = "%prog [options] name=value.."
    parser = optparse.OptionParser(usage=usage, version="%prog 0.1")
    parser.add_option('-g', '--guid',
                      action='store_true', dest='guid',
                      help="add guid=GUID to message. " +
                      "This is overridden by an explicit guid=GUID argument.")    
    parser.add_option('-i', '--ip',
                      action='store_true', dest='ipaddr', metavar='IP',
                      help="add 'host=IP' to message. " + 
                      "This is overridden by an explicit host=HOST argument.") 
    parser.add_option('-n', '--num', metavar='NUM',
                      action='store', type='int', dest='num', default=1,
                      help="Write NUM messages, each with n=<1..NUM> in them"
                      " (default=%default)")
    parser.add_option('-H', '--host',
                      action='store', dest='host', default="localhost",
                      help="for UDP/TCP, the remote host (default=%default)")
    parser.add_option('-P', '--port', action="store", type="int",
                      dest="port", metavar="PORT", default=-1,
                      help="For UDP/TCP, the port to write to " + 
                      "(default=UDP %d, TCP %d)" % 
                      (_P['udp_port'], _P['tcp_port']))
    parser.add_option('-S', '--syslog', action="store_true", default=None,
                      dest="syslog_hdr",
                      help="add a header for syslog (default=False unless " +
                      "-U is given, then True)")                   
    parser.add_option('-T', '--tcp', action="store_true", default=False, 
                      dest="tcp",
                      help="write message to TCP (default port=%d)" % 
                      _P['tcp_port']) 
    parser.add_option('-U', '--udp', action="store_true", default=False, 
                      dest="udp",
                      help="write message to UDP (default port=%d)" % 
                      _P['udp_port'])                                                    
    options, args= parser.parse_args()
    if options.tcp and options.udp:
        parser.error("both TCP and UDP options given, can only do one")
    # make argument into dictionary
    d = parseNVP(args, parser)
    # add values from options
    if options.guid:
        if d.has_key('guid'):
            _log.warn("guid option ignored with guid=* on command-line")
        else:
            d['guid'] = nlapi.getGuid()
    if options.ipaddr:
        if d.has_key('host'):
            _log.warn("ip option ignored with host=* on command-line")
        else:
            d['host'] = nlapi.getHost()
    # pull out required fields event and level
    if d.has_key('event'):
        event = d['event']
        del d['event']
    else:
        event = _P['event']
    if d.has_key('level'):
        levelstr = d['level']
        del d['level']
        # check level
        try:
            level = Level.getLevel(levelstr.upper())
        except ValueError:
            parser.error("bad level name '%s'" % levelstr)
    else:
        level = _P['level']
    # write message(s)
    log = nlapi.Log()
    for i in xrange(options.num):
        if options.num > 1:
            d['n'] = i
        logstr = log.write(event=event, level=level, **d)
        if options.syslog_hdr or (options.syslog_hdr is None and options.udp):
            logstr = syslogHeader(d.get('host', 'localhost')) + logstr
        if options.udp:
            port = (options.port, _P['udp_port'])[options.port < 0]
            sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
            sock.sendto(logstr, (options.host, port))    
            sock.close()
        elif options.tcp:
            port = (options.port, _P['tcp_port'])[options.port < 0]
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            try:
                sock.connect((options.host, port))
            except socket.error, E:
                _log.error("error: cannot connect to %s:%d: %s",
                           options.host, port, E)
                sys.exit(1)
            sock.send(logstr)
            sock.close()
        else:
            sys.stdout.write(logstr)
    
    
if __name__ == "__main__": 
    main()
