Skip to content

Commit 18eefd4

Browse files
author
swei
committed
run log history added
1 parent bf6733d commit 18eefd4

File tree

11 files changed

+323
-2
lines changed

11 files changed

+323
-2
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,5 @@ nosetests.xml
3636

3737
# Virtualenv
3838
venv
39+
40+
.DS_Store

dagobah/backend/sqlite.py

+26
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,32 @@ def get_latest_run_log(self, job_id, task_name):
211211
first()
212212
return log.json
213213

214+
def get_run_log_history(self, job_id, task_name):
215+
logs = self.session.query(DagobahLog).\
216+
filter_by(job_id=job_id).\
217+
order_by(DagobahLog.save_date.desc()).\
218+
all()
219+
result = []
220+
for log in logs:
221+
if task_name in log.json['tasks']:
222+
result.append(log.json)
223+
return result
224+
225+
def get_run_log(self, job_id, task_name, log_id):
226+
log = self.session.query(DagobahLog).\
227+
filter_by(job_id=job_id).\
228+
filter_by(id=log_id).\
229+
first()
230+
if log == None:
231+
return None
232+
start_time = log.json['start_time']
233+
if task_name in log.json['tasks']:
234+
result = log.json['tasks'][task_name]
235+
result['start_time'] = start_time
236+
return result
237+
else:
238+
return None
239+
214240
def acquire_lock(self):
215241
self.lock.acquire()
216242

dagobah/core/core.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,10 @@ def __init__(self, parent_job, command, name,
660660
self.command = command
661661
self.name = name
662662

663-
self.host_id = int(host_id)
663+
if host_id != None:
664+
self.host_id = int(host_id)
665+
else:
666+
self.host_id = host_id
664667
self.remote_process = None
665668

666669
self.process = None
@@ -760,6 +763,8 @@ def remote_ssh(self, stdout, stderr, exit_status, host):
760763
except Exception as e:
761764
stderr.value = str(e)
762765
exit_status.value = 1
766+
finally:
767+
client.close()
763768

764769

765770
def check_complete(self):
@@ -857,9 +862,23 @@ def tail(self, stream='stdout', num_lines=10):
857862
return self._tail_string(last_run['tasks'][self.name][stream],
858863
num_lines)
859864
else:
865+
return target
860866
return self._tail_temp_file(target, num_lines)
861867

862868

869+
def get_log_history(self):
870+
history = self.backend.get_run_log_history(self.parent_job.job_id, self.name)
871+
if not history:
872+
return None
873+
return history
874+
875+
876+
def get_log(self, log_id):
877+
log = self.backend.get_run_log(self.parent_job.job_id, self.name, log_id)
878+
if not log:
879+
return None
880+
return log
881+
863882
def get_stdout(self):
864883
""" Returns the entire stdout output of this process. """
865884
return self._read_temp_file(self.stdout_file)

dagobah/daemon/api.py

+40-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import StringIO
44
import json
55

6-
from flask import request, abort, send_file
6+
from flask import request, abort, send_file, jsonify
77
from flask_login import login_required
88

99
from dagobah.daemon.daemon import app
@@ -32,6 +32,43 @@ def get_job():
3232
return job._serialize()
3333

3434

35+
@app.route('/api/logs', methods=['GET'])
36+
@login_required
37+
@api_call
38+
def get_log_history():
39+
args = dict(request.args)
40+
if not validate_dict(args,
41+
required=['job_name', 'task_name'],
42+
job_name=str,
43+
task_name=str):
44+
abort(400)
45+
46+
job = dagobah.get_job(args['job_name'])
47+
task = job.tasks.get(args['task_name'], None)
48+
if not task:
49+
abort(400)
50+
return task.get_log_history()
51+
52+
53+
@app.route('/api/log', methods=['GET'])
54+
@login_required
55+
@api_call
56+
def get_log():
57+
args = dict(request.args)
58+
if not validate_dict(args,
59+
required=['job_name', 'task_name', 'log_id'],
60+
job_name=str,
61+
task_name=str,
62+
log_id=int):
63+
abort(400)
64+
65+
job = dagobah.get_job(args['job_name'])
66+
task = job.tasks.get(args['task_name'], None)
67+
if not task:
68+
abort(400)
69+
return task.get_log(args['log_id'])
70+
71+
3572
@app.route('/api/head', methods=['GET'])
3673
@login_required
3774
@api_call
@@ -444,3 +481,5 @@ def delete_host():
444481
abort(400)
445482

446483
dagobah.delete_host(args['host_name'])
484+
485+
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
.page-header h3 {
2+
display: inline-block;
3+
}
4+
5+
.right {
6+
text-align: right;
7+
}
8+
9+
.btn-sequence {
10+
margin-right: 10px;
11+
}
12+
13+
.page-header .right {
14+
float: right;
15+
}
16+
17+
textarea {
18+
margin-top: 20px;
19+
width: 100%;
20+
height: 400px;
21+
font-family: "Lucida Console", Monaco, monospace;
22+
}
23+
24+
.right-header {
25+
float: right;
26+
font-size: 26.25px;
27+
color: #2d2d2d;
28+
}
29+
30+
.span6 .alert {
31+
width: 80%;
32+
}
33+
34+
td:last-child {
35+
width: 8%;
36+
}

dagobah/daemon/static/css/task_detail.css

+4
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,7 @@ textarea {
3030
.span6 .alert {
3131
width: 80%;
3232
}
33+
34+
td:last-child {
35+
width: 8%;
36+
}
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
stdoutLog('stdout');
2+
3+
function stdoutLog(stream) {
4+
$.getJSON($SCRIPT_ROOT + '/api/log',
5+
{
6+
job_name: jobName,
7+
task_name: taskName,
8+
log_id: logId
9+
},
10+
function(data) {
11+
showLogText(stream, data['result'][stream], data['result']['start_time']);
12+
}
13+
);
14+
}
15+
16+
17+
$('#stderr').click(function() {
18+
stdoutLog('stderr')
19+
});
20+
21+
$('#stdout').click(function() {
22+
stdoutLog('stdout')
23+
});
24+
25+
function showLogText(logType, value, start_time) {
26+
$('#log-detail').text(value);
27+
$('#log-detail').scrollTop(0);
28+
$('#log-detail').removeClass('hidden');
29+
$('#log-type').text(logType);
30+
$('#header').text($('#header').text() + ' - ' + start_time);
31+
}

dagobah/daemon/static/js/task_detail.js

+75
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
2+
var historyTableTemplate = Handlebars.compile($('#history-table-template').html());
3+
var historyNameTemplate = Handlebars.compile($('#history-name-template').html());
4+
5+
Handlebars.registerPartial('historyId', historyNameTemplate);
6+
7+
var historyData = [];
8+
loadHistoryTable();
9+
110
$('#save-soft-timeout').click(function() {
211

312
$.ajax({
@@ -119,3 +128,69 @@ $('#tail-stderr').click(function() {
119128
);
120129

121130
});
131+
132+
133+
function loadHistoryTable() {
134+
135+
$.getJSON($SCRIPT_ROOT + '/api/logs',
136+
{
137+
job_name: jobName,
138+
task_name: taskName,
139+
},
140+
function(data) {
141+
data = data.result;
142+
renderHistoryTable(data);
143+
}
144+
);
145+
}
146+
147+
148+
function renderHistoryTable(data){
149+
if (data.length === 0) {
150+
setTimeout(renderHistoryTable, 100);
151+
return;
152+
}
153+
154+
$('#history-body').empty();
155+
156+
for (var i = 0; i < data.length; i++) {
157+
var thisJob = data[i];
158+
$('#history-body').append(
159+
historyTableTemplate({
160+
historyId: thisJob.log_id,
161+
logURL: $SCRIPT_ROOT + '/job/' + thisJob.job_id + '/' + taskName + '/' + thisJob.log_id
162+
})
163+
);
164+
}
165+
166+
$('#history-body').children().each(function() {
167+
var log_id = $(this).attr('data-log');
168+
for (var i = 0; i < data.length; i++) {
169+
if (data[i].log_id == log_id) {
170+
var job = data[i];
171+
break;
172+
}
173+
}
174+
175+
$(this).find('[data-attr]').each(function() {
176+
var attr = $(this).attr('data-attr');
177+
var transforms = $(this).attr('data-transform') || '';
178+
transforms = transforms.split(' ');
179+
180+
var descendants = $(this).children().clone(true);
181+
$(this).text('');
182+
if (job[attr] !== null) {
183+
$(this).text(job[attr]);
184+
}
185+
186+
for (var i = 0; i < transforms.length; i++) {
187+
var transform = transforms[i];
188+
applyTransformation($(this), job[attr], transform);
189+
}
190+
191+
$(this).append(descendants);
192+
193+
});
194+
195+
});
196+
}
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{% extends 'base.html' %}
2+
3+
{% block head %}
4+
{{ super() }}
5+
6+
<script>
7+
var jobName = '{{ job.name }}';
8+
var taskName = '{{ task_name }}';
9+
var logId = '{{ log_id }}';
10+
</script>
11+
12+
<link rel="stylesheet" href="/static/css/log_detail.css"></link>
13+
14+
{% endblock head %}
15+
16+
{% block navbar_current %}
17+
<li><a href='{{ url_for('job_detail', job_id=job.job_id) }}'>Job: {{ job.name }}</a></li>
18+
<li><a href='#'>Task Detail: {{ task_name }}</a></li>
19+
{% endblock navbar_current %}
20+
21+
{% block content %}
22+
23+
<div class='page-header'>
24+
<h3 id='header'>Run History: {{ task_name }}</h3>
25+
<h3 id='task-status' class='right'></h3>
26+
</div>
27+
28+
<div id='logs' class='row'>
29+
<div class='span12'>
30+
31+
<div class='log-controls'>
32+
<button id='stdout' class='btn btn-sequence btn-primary'>Stdout</button>
33+
<button id='stderr' class='btn btn-sequence btn-primary'>Stderr</button>
34+
35+
<span id='log-type' class='right-header'>Stdout</span>
36+
</div>
37+
38+
<textarea id='log-detail'></textarea>
39+
40+
</div>
41+
</div>
42+
43+
{% endblock content %}
44+
45+
{% block body_scripts %}
46+
<script src="/static/js/log_detail.js"></script>
47+
{% endblock body_scripts %}

dagobah/daemon/templates/task_detail.html

+30
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,26 @@
99
</script>
1010

1111
<link rel="stylesheet" href="/static/css/task_detail.css"></link>
12+
13+
{% raw %}
14+
<script id="history-table-template" type="text/x-handlebars-template">
15+
<tr data-log='{{ historyId }}'>
16+
{{> historyId }}
17+
<td><span data-attr='start_time' data-transform='class title'
18+
class={{ timestamp }}></span>
19+
</td>
20+
<td>
21+
<button class='btn btn-primary' onclick="window.location.href = '{{ logURL }}';">View</button>
22+
</td>
23+
</tr>
24+
</script>
25+
<script id="history-name-template" type="text/x-handlebars-template">
26+
<td data-attr='log_id'>
27+
{{#if historyId}}{{historyId}}{{/if}}
28+
</td>
29+
</script>
30+
{% endraw %}
31+
1232
{% endblock head %}
1333

1434
{% block navbar_current %}
@@ -100,6 +120,16 @@ <h3>Run Logs</h3>
100120
</div>
101121
</div>
102122

123+
<table class='table table-striped'>
124+
<thead>
125+
<th>Run ID</th>
126+
<th>Timestamp</th>
127+
<th></th>
128+
</thead>
129+
<tbody id='history-body'>
130+
</tbody>
131+
</table>
132+
103133
{% endblock content %}
104134

105135
{% block body_scripts %}

0 commit comments

Comments
 (0)