10 from datetime import datetime
12 from monitor import config
13 from monitor import database
15 def convert_time(time_str):
18 tup = time.strptime(str, "%Y-%m-%d %H:%M:%S")
20 tup = time.strptime(str, "%Y-%m-%d-%H:%M")
22 tup = time.strptime(str, "%m/%d/%Y")
24 tup = time.strptime(str, "%m/%d/%Y")
25 d_ret = datetime.fromtimestamp(time.mktime(tup))
31 rt_db = MySQLdb.connect(host=config.RT_DB_HOST,
32 user=config.RT_DB_USER,
33 passwd=config.RT_DB_PASSWORD,
35 except Exception, err:
36 print "Failed to connect to RT database: %s" %err
41 def fetch_from_db(db, sql):
43 # create a 'cursor' (required by MySQLdb)
46 except Exception, err:
47 print "Could not execute RT query %s" %err
50 # fetch all rows (list of lists)
56 print "open db connection"
61 sql = """SELECT tk.id, tk.Queue, tr.Type, tr.Field, tr.OldValue, tr.NewValue,
62 tr.Created, at.id, at.Subject, at.Content, us.Name
63 FROM Tickets as tk, Transactions as tr, Users as us
64 LEFT OUTER JOIN Attachments as at ON tr.id=at.TransactionId
65 WHERE (tk.Queue=22) AND tk.id=tr.ObjectId AND tk.id>40800 AND
67 #WHERE (tk.Queue=22) AND tk.id=tr.ObjectId AND tk.id>39896 AND tk.id<42241 AND ## (oct15th2008)
68 #WHERE (tk.Queue=22) AND tk.id=tr.ObjectId AND tk.id>40800 AND ## (1st3months)
69 #WHERE (tk.Queue=3 OR tk.Queue=22) AND tk.id=tr.ObjectId AND tk.id>10000 """
72 raw = fetch_from_db(db, sql)
85 datecreated = x[6] # already a datetime object
91 if ticket_id not in tickets:
92 print "found new ticket_id", ticket_id
93 tickets[ticket_id] = {'queue' : queue,
97 subject_map[ticket_id] = subject
98 elif ticket_id in subject_map:
99 subject = subject_map[ticket_id]
101 # subject == "" and no record in subject_map yet
102 # should probably put on a queue to be processed later.
103 print "no subject for %s" % ticket_id
108 'oldvalue' : oldvalue,
109 'newvalue' : newvalue,
110 'datecreated' : datecreated,
111 'attachmentid' : attachmentid,
116 tickets[ticket_id]['transactions'].append(transaction)
120 list = map(parse_ticket, raw)
131 # classify into category
132 # remove from ticket set, add to classified-set
134 # add new search patterns,
135 # re-run classify algorithm
138 #('mom', {'pattern' : '.*pl_mom.*'}),
139 #('technical-support', {'pattern' : '.*PlanetLab node.* down'}),
140 #('technical-support', {'pattern' : 'Node .* was stopped by'}), # and opened
141 #('technical-support', {'pattern' : 'bootcd|BootCD|bootCD|boot cd|boot CD|booting'}),
142 #('technical-support', {'pattern' : '.* failed to authenticate'}),
143 #('technical-support', {'pattern' : '.* fails to boot'}),
144 #('technical-support', {'pattern' : '.* fail.* to boot'}),
145 #('technical-support', {'pattern' : '.* failed to authenticate'}),
146 #('technical-support', {'pattern' : 'curl (60)|.* CA certificates.*|peer certificate.*authenticated'}),
147 #('technical-support', {'pattern' : '(usb|USB).*(key|Disk|stick|boot|help|problem|trouble)'}),
148 #('complaint', {'pattern' : '.*omplaint|.*attack'}),
149 #('complaint', {'pattern' : '.* stop .*'}), # and subject
151 #('user-support', {'pattern' : '(R|r)egistration|(R|r)egister'}),
152 #('user-support', {'pattern' : 'password reset|reset password'}),
153 ('user-support', {'pattern' : 'New PI account registration from'}),
157 def sort_tickets(tickets, re_map):
159 ticket_count = len(tickets.keys())
162 for ticket_id in sorted(tickets.keys()):
163 for i,(name, pattern) in enumerate(re_map):
164 if 'compile' not in pattern:
165 pattern['compile'] = re.compile(pattern['pattern'])
166 pat = pattern['compile']
167 for transaction in tickets[ticket_id]['transactions']:
170 if transaction['subject'] and re.match(pat, transaction['subject']):
171 print "ticket %s matches pattern %s: %s" % (ticket_id,
172 pattern['pattern'], transaction['subject'])
175 if transaction['content'] and re.match(pat, transaction['content']):
176 print "ticket %s matches pattern %s: %s" % (ticket_id,
177 pattern['pattern'], transaction['subject'])
178 #if transaction['subject'] == "":
184 print traceback.print_exc()
193 print ticket_count - marked_content - marked_content
196 from optparse import OptionParser
197 parser = OptionParser()
199 parser.set_defaults(runsql=False,)
201 parser.add_option("", "--runsql", dest="runsql", action="store_true",
202 help="Whether to collect data from the MySQL server before "+
203 "caching it, or to just use the previously collected data.")
205 (config, args) = parser.parse_args()
206 if len(sys.argv) == 1:
210 for i,(name, pattern) in enumerate(re_map):
214 tickets = get_rt_tickets()
215 database.dbDump("survey_tickets", tickets)
218 tickets = database.dbLoad("survey_tickets")
219 #print tickets[42171]['transactions'][0]
221 #sort_tickets(tickets, re_map)
224 # scan for known keywords and sort into classes
225 # record assigned class
227 # review all tickets that remain
229 if __name__ == '__main__':