Tweaks
[pylnprof.git] / pylnprof.py
1 #!/usr/bin/python
2
3 import sys
4 import os
5 import time
6 import signal
7
8 from optparse import OptionParser
9
10 LNPROF_NS = 'test'
11 LNPROF_NODEID=0
12 LNPROF_ROOT='/'
13
14 def get_nodeid(ns=LNPROF_NS):
15     node_id_file = '/etc/lnprof-%s'%ns
16     try:
17         node_id = open(node_id_file).read().rstrip()
18     except IOError:
19         hostname = os.popen('/usr/bin/hostname').read().rstrip()
20         node_id = os.popen('wget www.lnprof.org/command?action=getnode&ns=%s&hostname=%s'%(ns,hostname)).read().rstrip()
21         open(node_id_file).write(node_id)
22     return node_id
23
24
25 def excepthook(t, val, tb):
26     exc_name = str(t)
27     exc_name = exc_name[18:].split("'")[0]     
28
29     count=3
30     exc=[]
31     while (count>0 and tb):
32         s = "%s:%s"%(tb.tb_frame.f_code.co_filename,tb.tb_frame.f_code.co_firstlineno)
33         s=s.replace('.','')
34         s=s.replace('/','')
35         exc.append(s)
36         tb = tb.tb_next
37         count = count - 1
38
39     inp = {'root':LNPROF_ROOT,'trace':'/'.join(exc),'exc_name':exc_name,'val':val}
40     log_path = """
41     %(root)sError/%(exc_name)s/%(trace)s/%(val)s
42     """%inp
43
44     pushlog(get_nodeid(),log_path)
45     runcron()
46
47 def handler(signum, frame):
48     if (signum==signal.SIGALRM):
49         runcron()
50
51 def runcron():
52     last_sync_file='/tmp/lnprof-sync-%s-%s'%(LNPROF_NS,LNPROF_NODEID)
53     stamp = False
54     try:
55         last_stamp = int(open(last_sync_file).read())
56         now = int(time.time())
57         if (now-last_stamp>=300):
58             commit(get_nodeid())
59             stamp = True
60     except:
61         stamp = True
62
63     if (stamp):
64         s='%d'%int(time.time())
65         open(last_sync_file,'w').write(s)
66         signal.signal(signal.SIGALRM, handler)
67         signal.alarm(300)
68
69
70 sys.excepthook = excepthook
71
72 def pushlog(log_path,node_id=LNPROF_NODEID,ns=LNPROF_NS):
73     cache = open('/tmp/lnprof-%s-%s'%(ns,nodeid),'a') 
74     cache.write(log_path+'\n')
75
76 def commit(node_id=LNPROF_NODEID,ns=LNPROF_NS):
77     logpaths = {}
78     for i in range(0,1024):
79         si = '%d'%i
80         try:
81             fname = '/tmp/lnprof-%s-%d'%(ns,i)
82             logs = open(fname).readlines()
83             logs = map(lambda l:l.rstrip(),logs)
84             for l in logs:
85                 try:
86                     try:
87                         logpaths[l]['nodeset'].add(si)
88                     except KeyError:
89                         logpaths[l]={'nodeset':set([si])}
90                 except AttributeError:
91                     logpaths[l].nodeset = set([si])
92             if (not pretend):
93                 os.remove(fname)
94         except IOError:
95             pass
96     for k in logpaths.keys():
97         nodeset = list(logpaths[k]['nodeset'])
98         data = options
99         command = '/usr/bin/curl -s --cookie /tmp/fil --cookie-jar /tmp/fil -o - --data \'action=pushlog_nodes&ns=%s&nodes=%s&log_path=%s http://www.lnprof.org/command?pushlog_nodes >> /tmp/src.html'%(data.ns,','.join(nodeset),k)
100         if (pretend):
101             print command
102         else:
103             os.system(command)
104
105 def main():
106     parser = OptionParser()
107     parser.add_option("-l", "--log-path", dest="log_path",
108                   help="Log path to push", metavar="PATH")
109     parser.add_option("-n", "--nodeid",
110                   dest="nodeid", 
111                   help="Lnprof node id")
112     parser.add_option("-N", "--namespace",
113                   dest="ns", 
114                   help="Lnprof namespace")
115     parser.add_option("-k", "--api-key", dest="key",
116                   help="API key for your app", metavar="KEY", default = '')
117     parser.add_option("-p", "--pretend",
118                   dest="pretend", default=False, action="store_true",
119                   help="don't run only print")
120
121     (options, args) = parser.parse_args ()
122
123     try:
124         action = args[0]
125         if (action not in ["pushlog","commit"]):
126             raise Exception("bad action")
127     except:
128         print "Action needs to be one of pushlog and commit"
129         return
130
131     if (action=="pushlog"):
132         pushlog(options.log_path, options.node_id, options.ns)
133     elif (action=="commit"):
134         commit(options.log_path, options.node_id, options.ns) 
135
136 if __name__ == '__main__':
137     main()