Description:
add more logging
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r174:09d1e857c1e3 - - 3 files changed: 17 inserted, 3 deleted

@@ -12,173 +12,178
12 12 FileTest.exist?(File.dirname(__FILE__) + "/stop.all") or
13 13 FileTest.exist?(File.dirname(__FILE__) + "/stop.#{Process.pid}")
14 14 end
15 15
16 16 def clear_stopfile
17 17 if FileTest.exist?(File.dirname(__FILE__) + "/stop.#{Process.pid}")
18 18 File.delete(File.dirname(__FILE__) + "/stop.#{Process.pid}")
19 19 end
20 20 end
21 21
22 22 def config
23 23 Grader::Configuration.get_instance
24 24 end
25 25
26 26 def log_file_name
27 27 if !File.exists?(config.log_dir)
28 28 raise "Log directory does not exist: #{config.log_dir}"
29 29 end
30 30 config.log_dir +
31 31 "/#{GRADER_ENV}_#{config.grader_mode}.#{Process.pid}"
32 32 end
33 33
34 34 def log(str)
35 35 if config.talkative
36 36 puts str
37 37 end
38 38 if config.logging
39 39 fp = File.open(log_file_name,"a")
40 40 fp.puts("GRADER: #{Time.new.strftime("%H:%M")} #{str}")
41 41 fp.close
42 42 end
43 43 end
44 44
45 45 def display_manual
46 46 puts <<USAGE
47 47 Grader.
48 48 using: (1) grader
49 49 (2) grader environment [mode] [options]
50 50 (3) grader stop [all|pids-list]
51 51 (4) grader --help
52 52 (1) call grader with environment = 'exam', mode = 'queue'
53 53 (2) possible modes are: 'queue', 'test_request', 'prob', 'sub', 'contest', and 'autonew'
54 54 queue: repeatedly check the task queue and grade any available tasks
55 55
56 56 prob: re-grade every user latest submission of the specific problem.
57 57 the problem name must be specified by the next argument.
58 58
59 59 additional options:
60 + --all-sub re-grade every submissions instead of just the latest submission of each user.
60 61
61 - --all-sub re-grade every submissions instead of just the latest submission of each user.
62 62 sub: re-grader the specified submission.
63 63 The submission ID to be re-graded must be specified by the next argument.
64 64
65 + options:
66 + --err-log log error to a file in the log dir
67 +
65 68 (3) create stop-file to stop running grader in queue mode
66 69 (4) You are here.
67 70 USAGE
68 71 end
69 72
70 73 def process_options_and_stop_file
71 74 # The list of options are:
72 75 # - stop [all|process ids]
73 76 # -
74 77
75 78 # Process 'help' option
76 79 if (ARGV.length==1) and (/help/.match(ARGV[0]))
77 80 display_manual
78 81 exit(0)
79 82 end
80 83
81 84 # Process 'stop' option.
82 85 if (ARGV.length >= 1) and (ARGV[0]=='stop')
83 86 if ARGV.length==1
84 87 puts "you should specify pid-list or 'all'"
85 88 display_manual
86 89 elsif (ARGV.length==2) and (ARGV[1]=='all')
87 90 stop_grader(:all)
88 91 puts "A global stop file ('stop.all') created."
89 92 puts "You should remove it manually later."
90 93 else
91 94 (1..ARGV.length-1).each do |i|
92 95 stop_grader(ARGV[i])
93 96 end
94 97 puts "stop file(s) created"
95 98 end
96 99 exit(0)
97 100 end
98 101
99 102 # Check stop file.
100 103 if check_stopfile
101 104 puts "Stop file exists. Terminated."
102 105 clear_stopfile
103 106 exit(0)
104 107 end
105 108
106 109 #default options
107 110 options = {
108 111 :mode => 'queue',
109 112 :environment => 'exam',
110 113 :dry_run => false,
111 114 }
112 115
113 116 # Process mode and environment option
114 117 if ARGV.length >= 1
115 118 options[:environment] = ARGV.shift
116 119 if ARGV.length >=1
117 120 options[:mode] = ARGV.shift
118 121 end
119 122 else
120 123 puts 'no argument specified, using default mode and environment.'
121 124 end
122 125
123 126 options[:dry_run] = (ARGV.delete('--dry') != nil)
124 127 if options[:dry_run] and (not ['prob','contest','autonew'].include? options[:mode])
125 128 puts "Dry run currently works only for 'prob' or 'contest' modes."
126 129 exit(0)
127 130 end
128 131
129 132 options[:report] = (ARGV.delete('--report') != nil)
130 133 if options[:report] and (not ['prob','contest','autonew'].include? options[:mode])
131 134 puts "Report currently works only for 'prob' or 'contest' modes."
132 135 exit(0)
133 136 end
134 137
135 138 options[:all_sub] = (ARGV.delete('--all-sub') != nil)
136 139
140 + options[:err_log] = (ARGV.delete('--err-log') != nil)
141 +
137 142 return options
138 143 end
139 144
140 145 class ResultCollector
141 146 def initialize
142 147 @results = {}
143 148 @problems = {}
144 149 @users = {}
145 150 end
146 151
147 152 def after_save_hook(submission, grading_result)
148 153 end
149 154
150 155 def save(submission, grading_result)
151 156 user = submission.user
152 157 problem = submission.problem
153 158 if not @problems.has_key? problem.id
154 159 @problems[problem.id] = problem
155 160 end
156 161 if not @users.has_key? user.id
157 162 @users[user.id] = user
158 163 end
159 164 @results[[user.id, problem.id]] = grading_result
160 165
161 166 after_save_hook(submission, grading_result)
162 167 end
163 168
164 169 def print_report_by_user
165 170 puts "---------------------"
166 171 puts " REPORT"
167 172 puts "---------------------"
168 173
169 174 print "login,email"
170 175 @problems.each_value do |problem|
171 176 print ",#{problem.name}"
172 177 end
173 178 print "\n"
174 179
175 180 @users.each_value do |user|
176 181 print "#{user.login},#{user.email}"
177 182 @problems.each_value do |problem|
178 183 if @results.has_key? [user.id, problem.id]
179 184 print ",#{@results[[user.id,problem.id]][:points]}"
180 185 else
181 186 print ","
182 187 end
183 188 end
184 189 print "\n"
@@ -375,85 +380,92
375 380 rescue ActiveRecord::RecordNotFound
376 381 puts "Submission #{sub_id} not found"
377 382 submission = nil
378 383 end
379 384
380 385 if submission!=nil
381 386 runner.grade_submission(submission)
382 387 end
383 388 end
384 389 end
385 390
386 391 #########################################
387 392 # main program
388 393 #########################################
389 394
390 395 options = process_options_and_stop_file
391 396 GRADER_ENV = options[:environment]
392 397 grader_mode = options[:mode]
393 398 dry_run = options[:dry_run]
394 399
395 400 puts "environment: #{GRADER_ENV}"
396 401 puts "grader mode: #{grader_mode}"
397 402 require File.join(File.dirname(__FILE__),'config/environment')
398 403
399 404 # add grader_mode to config
400 405 # this is needed because method log needs it. TODO: clean this up
401 406 class << config
402 407 attr_accessor :grader_mode
403 408 end
404 409 config.grader_mode = grader_mode
405 410
406 411 # reading rails environment
407 412 log 'Reading rails environment'
408 413
409 414 RAILS_ENV = config.rails_env
410 415 require RAILS_ROOT + '/config/environment'
411 416
412 417 # register grader process
413 418 if config.report_grader
414 419 grader_proc = GraderProcess.register(config.grader_hostname,
415 420 Process.pid,
416 421 grader_mode)
417 422 else
418 423 grader_proc = nil
419 424 end
420 425
421 426 #set loggin environment
422 427 ENV['GRADER_LOGGING'] = log_file_name
428 + if options[:err_log]
429 + err_file_name = log_file_name + '.err'
430 + $stderr.reopen(err_file_name,"a")
431 + log "STDERR log to file [#{err_file_name}]"
432 + warn "start logging for grader PID #{Process.id} on #{Time.now.in_time_zone}"
433 + end
434 +
423 435
424 436 # register exit handler to report inactive, and terminated
425 437 at_exit do
426 438 if grader_proc!=nil
427 439 grader_proc.report_inactive
428 440 grader_proc.terminate
429 441 end
430 442 end
431 443
432 444 #
433 445 # MAIN LOOP
434 446 #
435 447
436 448 case grader_mode
437 449 when "queue"
438 450 grader_queue_loop(grader_proc, options)
439 451
440 452 when "test_request"
441 453 grader_test_request_loop(grader_proc, options)
442 454
443 455 when "prob"
444 456 grader_grade_problems(grader_proc, options)
445 457
446 458 when "contest"
447 459 grader_grade_contests(grader_proc, options)
448 460
449 461 when "sub"
450 462 grader_grade_submissions(grader_proc, options)
451 463
452 464 when "autonew"
453 465 grader_autonew_loop(grader_proc, options)
454 466
455 467 else
456 468 display_manual
457 469 exit(0)
458 470 end
459 471
@@ -73,98 +73,100
73 73 # puts "PROBLEM DIR: #{problem_home}"
74 74
75 75 if !FileTest.exist?(problem_home)
76 76 puts "PROBLEM DIR: #{problem_home}"
77 77 raise "engine: No test data."
78 78 end
79 79
80 80 dinit = DirInit::Manager.new(problem_home)
81 81
82 82 dinit.setup do
83 83 copy_log = copy_script(problem_home)
84 84 save_copy_log(problem_home,copy_log)
85 85 end
86 86
87 87 call_judge(problem_home,language,grading_dir,source_name)
88 88
89 89 @reporter.report(submission,"#{grading_dir}/test-result")
90 90
91 91 dinit.teardown do
92 92 copy_log = load_copy_log(problem_home)
93 93 clear_copy_log(problem_home)
94 94 clear_script(copy_log,problem_home)
95 95 end
96 96
97 97 rescue RuntimeError => msg
98 98 @reporter.report_error(submission, msg)
99 99 puts "ERROR: #{msg}"
100 100
101 101 ensure
102 102 @room_maker.clean_up(submission)
103 103 Dir.chdir(current_dir) # this is really important
104 104 end
105 105 end
106 106
107 107 protected
108 108
109 109 def talk(str)
110 110 if @config.talkative
111 111 puts str
112 112 end
113 113 end
114 114
115 115 def call_judge(problem_home,language,grading_dir,fname)
116 116 ENV['PROBLEM_HOME'] = problem_home
117 117 ENV['RUBYOPT'] = ''
118 118
119 119 talk grading_dir
120 120 Dir.chdir grading_dir
121 - cmd = "#{problem_home}/script/judge #{language} #{fname}"
121 + script_name = "#{problem_home}/script/judge"
122 + cmd = "#{script_name} #{language} #{fname}"
122 123 talk "CMD: #{cmd}"
124 + warn "ERROR: file does not exists #{script_name}" unless File.exists? script_name
123 125 system(cmd)
124 126 end
125 127
126 128 def get_std_script_dir
127 129 GRADER_ROOT + '/std-script'
128 130 end
129 131
130 132 def copy_script(problem_home)
131 133 script_dir = "#{problem_home}/script"
132 134 std_script_dir = get_std_script_dir
133 135
134 136 raise "engine: std-script directory not found" if !FileTest.exist?(std_script_dir)
135 137
136 138 scripts = Dir[std_script_dir + '/*']
137 139
138 140 copied = []
139 141
140 142 scripts.each do |s|
141 143 fname = File.basename(s)
142 144 next if FileTest.directory?(s)
143 145 if !FileTest.exist?("#{script_dir}/#{fname}")
144 146 copied << fname
145 147 FileUtils.cp(s, "#{script_dir}", :preserve => true)
146 148 end
147 149 end
148 150
149 151 return copied
150 152 end
151 153
152 154 def copy_log_filename(problem_home)
153 155 return File.join(problem_home, '.scripts_copied')
154 156 end
155 157
156 158 def save_copy_log(problem_home, log)
157 159 f = File.new(copy_log_filename(problem_home),"w")
158 160 log.each do |fname|
159 161 f.write("#{fname}\n")
160 162 end
161 163 f.close
162 164 end
163 165
164 166 def load_copy_log(problem_home)
165 167 f = File.new(copy_log_filename(problem_home),"r")
166 168 log = []
167 169 f.readlines.each do |line|
168 170 log << line.strip
169 171 end
170 172 f.close
@@ -1,67 +1,67
1 1 #
2 2 # A runner drives the engine into various tasks.
3 3 #
4 4
5 5 module Grader
6 6
7 7 class Runner
8 8
9 9 def initialize(engine, grader_process=nil)
10 10 @engine = engine
11 11 @grader_process = grader_process
12 12 end
13 13
14 14 def grade_oldest_task
15 15 task = Task.get_inqueue_and_change_status(Task::STATUS_GRADING)
16 16 if task!=nil
17 17 @grader_process.report_active(task) if @grader_process!=nil
18 18
19 19 submission = Submission.find(task.submission_id)
20 20 @engine.grade(submission)
21 21 task.status_complete!
22 22 @grader_process.report_inactive(task) if @grader_process!=nil
23 23 end
24 24 return task
25 25 end
26 26
27 27 def grade_problem(problem, options={})
28 28 User.find_each do |u|
29 29 puts "user: #{u.login}"
30 30 if options[:user_conditions]!=nil
31 31 con_proc = options[:user_conditions]
32 32 next if not con_proc.call(u)
33 33 end
34 34 if options[:all_sub]
35 35 Submission.where(user_id: u.id,problem_id: problem.id).find_each do |sub|
36 36 @engine.grade(sub)
37 37 end
38 38 else
39 39 last_sub = Submission.find_last_by_user_and_problem(u.id,problem.id)
40 40 if last_sub!=nil
41 41 @engine.grade(last_sub)
42 42 end
43 43 end
44 44 end
45 45 end
46 46
47 47 def grade_submission(submission)
48 - puts "Submission: #{submission.id} by #{submission.user.full_name}"
48 + puts "Submission: #{submission.id} by #{submission.try(:user).try(:full_name)}"
49 49 @engine.grade(submission)
50 50 end
51 51
52 52 def grade_oldest_test_request
53 53 test_request = TestRequest.get_inqueue_and_change_status(Task::STATUS_GRADING)
54 54 if test_request!=nil
55 55 @grader_process.report_active(test_request) if @grader_process!=nil
56 56
57 57 @engine.grade(test_request)
58 58 test_request.status_complete!
59 59 @grader_process.report_inactive(test_request) if @grader_process!=nil
60 60 end
61 61 return test_request
62 62 end
63 63
64 64 end
65 65
66 66 end
67 67
You need to be logged in to leave comments. Login now