feature: Logs table creates an entry as soon as the execution is started (#464)
This commit is contained in:
parent
964dc7b48a
commit
1bfb7c4b28
|
|
@ -199,6 +199,10 @@ message EventExecutionFinished {
|
||||||
LogEntry log_entry = 1;
|
LogEntry log_entry = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message EventExecutionStarted {
|
||||||
|
LogEntry log_entry = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message KillActionRequest {
|
message KillActionRequest {
|
||||||
string execution_tracking_id = 1;
|
string execution_tracking_id = 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ func DefaultExecutor(cfg *config.Config) *Executor {
|
||||||
}
|
}
|
||||||
|
|
||||||
type listener interface {
|
type listener interface {
|
||||||
OnExecutionStarted(actionTitle string)
|
OnExecutionStarted(logEntry *InternalLogEntry)
|
||||||
OnExecutionFinished(logEntry *InternalLogEntry)
|
OnExecutionFinished(logEntry *InternalLogEntry)
|
||||||
OnOutputChunk(o []byte, executionTrackingId string)
|
OnOutputChunk(o []byte, executionTrackingId string)
|
||||||
OnActionMapRebuilt()
|
OnActionMapRebuilt()
|
||||||
|
|
@ -233,7 +233,7 @@ func (e *Executor) execChain(req *ExecutionRequest) {
|
||||||
|
|
||||||
// This isn't a step, because we want to notify all listeners, irrespective
|
// This isn't a step, because we want to notify all listeners, irrespective
|
||||||
// of how many steps were actually executed.
|
// of how many steps were actually executed.
|
||||||
notifyListeners(req)
|
notifyListenersFinished(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getConcurrentCount(req *ExecutionRequest) int {
|
func getConcurrentCount(req *ExecutionRequest) int {
|
||||||
|
|
@ -400,6 +400,8 @@ func stepRequestAction(req *ExecutionRequest) bool {
|
||||||
"tags": req.Tags,
|
"tags": req.Tags,
|
||||||
}).Infof("Action requested")
|
}).Infof("Action requested")
|
||||||
|
|
||||||
|
notifyListenersStarted(req)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -425,12 +427,18 @@ func stepLogFinish(req *ExecutionRequest) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func notifyListeners(req *ExecutionRequest) {
|
func notifyListenersFinished(req *ExecutionRequest) {
|
||||||
for _, listener := range req.executor.listeners {
|
for _, listener := range req.executor.listeners {
|
||||||
listener.OnExecutionFinished(req.logEntry)
|
listener.OnExecutionFinished(req.logEntry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func notifyListenersStarted(req *ExecutionRequest) {
|
||||||
|
for _, listener := range req.executor.listeners {
|
||||||
|
listener.OnExecutionStarted(req.logEntry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func appendErrorToStderr(err error, logEntry *InternalLogEntry) {
|
func appendErrorToStderr(err error, logEntry *InternalLogEntry) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logEntry.Output = err.Error() + "\n\n" + logEntry.Output
|
logEntry.Output = err.Error() + "\n\n" + logEntry.Output
|
||||||
|
|
|
||||||
|
|
@ -35,13 +35,10 @@ var ExecutionListener WebsocketExecutionListener
|
||||||
|
|
||||||
type WebsocketExecutionListener struct{}
|
type WebsocketExecutionListener struct{}
|
||||||
|
|
||||||
func (WebsocketExecutionListener) OnExecutionStarted(title string) {
|
func (WebsocketExecutionListener) OnExecutionStarted(ile *executor.InternalLogEntry) {
|
||||||
/*
|
broadcast(&pb.EventExecutionStarted{
|
||||||
broadcast(ExecutionStarted{
|
LogEntry: internalLogEntryToPb(ile),
|
||||||
Type: "ExecutionStarted",
|
});
|
||||||
Action: title,
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func OnEntityChanged() {
|
func OnEntityChanged() {
|
||||||
|
|
@ -82,22 +79,7 @@ func (WebsocketExecutionListener) OnOutputChunk(chunk []byte, executionTrackingI
|
||||||
|
|
||||||
func (WebsocketExecutionListener) OnExecutionFinished(logEntry *executor.InternalLogEntry) {
|
func (WebsocketExecutionListener) OnExecutionFinished(logEntry *executor.InternalLogEntry) {
|
||||||
evt := &pb.EventExecutionFinished{
|
evt := &pb.EventExecutionFinished{
|
||||||
LogEntry: &pb.LogEntry{
|
LogEntry: internalLogEntryToPb(logEntry),
|
||||||
ActionTitle: logEntry.ActionTitle,
|
|
||||||
ActionIcon: logEntry.ActionIcon,
|
|
||||||
ActionId: logEntry.ActionId,
|
|
||||||
DatetimeStarted: logEntry.DatetimeStarted.Format("2006-01-02 15:04:05"),
|
|
||||||
DatetimeFinished: logEntry.DatetimeFinished.Format("2006-01-02 15:04:05"),
|
|
||||||
Output: logEntry.Output,
|
|
||||||
TimedOut: logEntry.TimedOut,
|
|
||||||
Blocked: logEntry.Blocked,
|
|
||||||
ExitCode: logEntry.ExitCode,
|
|
||||||
Tags: logEntry.Tags,
|
|
||||||
ExecutionTrackingId: logEntry.ExecutionTrackingID,
|
|
||||||
ExecutionStarted: logEntry.ExecutionStarted,
|
|
||||||
ExecutionFinished: logEntry.ExecutionFinished,
|
|
||||||
User: logEntry.Username,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Execution finished: %v+v", evt.LogEntry)
|
log.Infof("Execution finished: %v+v", evt.LogEntry)
|
||||||
|
|
@ -178,3 +160,23 @@ func HandleWebsocket(w http.ResponseWriter, r *http.Request) bool {
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func internalLogEntryToPb(logEntry *executor.InternalLogEntry) *pb.LogEntry {
|
||||||
|
return &pb.LogEntry{
|
||||||
|
ActionTitle: logEntry.ActionTitle,
|
||||||
|
ActionIcon: logEntry.ActionIcon,
|
||||||
|
ActionId: logEntry.ActionId,
|
||||||
|
DatetimeStarted: logEntry.DatetimeStarted.Format("2006-01-02 15:04:05"),
|
||||||
|
DatetimeFinished: logEntry.DatetimeFinished.Format("2006-01-02 15:04:05"),
|
||||||
|
Output: logEntry.Output,
|
||||||
|
TimedOut: logEntry.TimedOut,
|
||||||
|
Blocked: logEntry.Blocked,
|
||||||
|
ExitCode: logEntry.ExitCode,
|
||||||
|
Tags: logEntry.Tags,
|
||||||
|
ExecutionTrackingId: logEntry.ExecutionTrackingID,
|
||||||
|
ExecutionStarted: logEntry.ExecutionStarted,
|
||||||
|
ExecutionFinished: logEntry.ExecutionFinished,
|
||||||
|
User: logEntry.Username,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,12 +54,13 @@ export function initMarshaller () {
|
||||||
|
|
||||||
window.executionDialog = new ExecutionDialog()
|
window.executionDialog = new ExecutionDialog()
|
||||||
|
|
||||||
window.logEntries = {}
|
window.logEntries = new Map()
|
||||||
window.registeredPaths = new Map()
|
window.registeredPaths = new Map()
|
||||||
window.breadcrumbNavigation = []
|
window.breadcrumbNavigation = []
|
||||||
|
|
||||||
window.currentPath = ''
|
window.currentPath = ''
|
||||||
|
|
||||||
|
window.addEventListener('EventExecutionStarted', onExecutionStarted)
|
||||||
window.addEventListener('EventExecutionFinished', onExecutionFinished)
|
window.addEventListener('EventExecutionFinished', onExecutionFinished)
|
||||||
window.addEventListener('EventOutputChunk', onOutputChunk)
|
window.addEventListener('EventOutputChunk', onOutputChunk)
|
||||||
}
|
}
|
||||||
|
|
@ -125,6 +126,14 @@ function onOutputChunk (evt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onExecutionStarted (evt) {
|
||||||
|
const logEntry = evt.payload.logEntry
|
||||||
|
|
||||||
|
marshalLogsJsonToHtml({
|
||||||
|
logs: [logEntry]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function onExecutionFinished (evt) {
|
function onExecutionFinished (evt) {
|
||||||
const logEntry = evt.payload.logEntry
|
const logEntry = evt.payload.logEntry
|
||||||
|
|
||||||
|
|
@ -136,7 +145,9 @@ function onExecutionFinished (evt) {
|
||||||
|
|
||||||
switch (actionButton.popupOnStart) {
|
switch (actionButton.popupOnStart) {
|
||||||
case 'execution-button':
|
case 'execution-button':
|
||||||
document.querySelector('execution-button#execution-' + logEntry.executionTrackingId).onExecutionFinished(logEntry)
|
if (document.querySelector('execution-button#execution-' + logEntry.executionTrackingId) !== null) { // If the button was created in our instance
|
||||||
|
document.querySelector('execution-button#execution-' + logEntry.executionTrackingId).onExecutionFinished(logEntry)
|
||||||
|
}
|
||||||
break
|
break
|
||||||
case 'execution-dialog-stdout-only':
|
case 'execution-dialog-stdout-only':
|
||||||
case 'execution-dialog':
|
case 'execution-dialog':
|
||||||
|
|
@ -617,41 +628,46 @@ function marshalDirectory (item, section) {
|
||||||
|
|
||||||
export function marshalLogsJsonToHtml (json) {
|
export function marshalLogsJsonToHtml (json) {
|
||||||
for (const logEntry of json.logs) {
|
for (const logEntry of json.logs) {
|
||||||
const existing = window.logEntries[logEntry.executionTrackingId]
|
let row
|
||||||
|
|
||||||
if (existing !== undefined) {
|
if (window.logEntries.has(logEntry.executionTrackingId)) {
|
||||||
continue
|
row = window.logEntries.get(logEntry.executionTrackingId).dom
|
||||||
|
} else {
|
||||||
|
const tpl = document.getElementById('tplLogRow')
|
||||||
|
row = tpl.content.querySelector('tr').cloneNode(true)
|
||||||
|
|
||||||
|
row.querySelector('.content').onclick = () => {
|
||||||
|
window.executionDialog.reset()
|
||||||
|
window.executionDialog.show()
|
||||||
|
window.executionDialog.renderExecutionResult({
|
||||||
|
logEntry: window.logEntries.get(logEntry.executionTrackingId)
|
||||||
|
})
|
||||||
|
pushNewNavigationPath('/logs/' + logEntry.executionTrackingId)
|
||||||
|
}
|
||||||
|
|
||||||
|
row.exitCodeDisplay = new ActionStatusDisplay(row.querySelector('.exit-code'))
|
||||||
|
|
||||||
|
logEntry.dom = row
|
||||||
|
|
||||||
|
window.logEntries.set(logEntry.executionTrackingId, logEntry)
|
||||||
|
|
||||||
|
document.querySelector('#logTableBody').prepend(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
window.logEntries[logEntry.executionTrackingId] = logEntry
|
|
||||||
|
|
||||||
const tpl = document.getElementById('tplLogRow')
|
|
||||||
const row = tpl.content.querySelector('tr').cloneNode(true)
|
|
||||||
|
|
||||||
row.querySelector('.timestamp').innerText = logEntry.datetimeStarted
|
row.querySelector('.timestamp').innerText = logEntry.datetimeStarted
|
||||||
row.querySelector('.content').innerText = logEntry.actionTitle
|
row.querySelector('.content').innerText = logEntry.actionTitle
|
||||||
row.querySelector('.icon').innerHTML = logEntry.actionIcon
|
row.querySelector('.icon').innerHTML = logEntry.actionIcon
|
||||||
row.setAttribute('title', logEntry.actionTitle)
|
row.setAttribute('title', logEntry.actionTitle)
|
||||||
|
|
||||||
const exitCodeDisplay = new ActionStatusDisplay(row.querySelector('.exit-code'))
|
row.exitCodeDisplay.update(logEntry)
|
||||||
exitCodeDisplay.update(logEntry)
|
|
||||||
|
|
||||||
row.querySelector('.content').onclick = () => {
|
row.querySelector('.tags').innerHTML = ''
|
||||||
window.executionDialog.reset()
|
|
||||||
window.executionDialog.show()
|
|
||||||
window.executionDialog.renderExecutionResult({
|
|
||||||
logEntry: window.logEntries[logEntry.executionTrackingId]
|
|
||||||
})
|
|
||||||
pushNewNavigationPath('/logs/' + logEntry.executionTrackingId)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const tag of logEntry.tags) {
|
for (const tag of logEntry.tags) {
|
||||||
row.querySelector('.tags').append(createTag(tag))
|
row.querySelector('.tags').append(createTag(tag))
|
||||||
}
|
}
|
||||||
|
|
||||||
row.querySelector('.tags').append(createAnnotation('user', logEntry.user))
|
row.querySelector('.tags').append(createAnnotation('user', logEntry.user))
|
||||||
|
|
||||||
document.querySelector('#logTableBody').prepend(row)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ function websocketOnMessage (msg) {
|
||||||
case 'EventOutputChunk':
|
case 'EventOutputChunk':
|
||||||
case 'EventConfigChanged':
|
case 'EventConfigChanged':
|
||||||
case 'EventExecutionFinished':
|
case 'EventExecutionFinished':
|
||||||
|
case 'EventExecutionStarted':
|
||||||
case 'EventEntityChanged':
|
case 'EventEntityChanged':
|
||||||
window.dispatchEvent(e)
|
window.dispatchEvent(e)
|
||||||
break
|
break
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue