Skip to content

Commit

Permalink
implant: capture internal error logs and expose them via reporter
Browse files Browse the repository at this point in the history
  • Loading branch information
darwin committed Aug 21, 2016
1 parent 7131b62 commit d853110
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 28 deletions.
1 change: 1 addition & 0 deletions resources/unpacked/devtools/front_end/externs.js
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ var dirac = {

triggerInternalError: function() {},
triggerInternalErrorInPromise: function() {},
triggerInternalErrorAsErrorLog: function() {},
/**
* @param {string} name
* @return {string}
Expand Down
5 changes: 5 additions & 0 deletions src/automation/dirac/automation.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@
:kind :unhandled-exception-in-promise
:delay (or delay 100)}))

(defn trigger-internal-error-as-error-log! [devtools-id & [delay]]
(automate-dirac-frontend! devtools-id {:action :trigger-internal-error
:kind :error-log
:delay (or delay 100)}))

(defn scrape [devtools-id scraper-name & args]
(automate-dirac-frontend! devtools-id {:action :scrape
:scraper scraper-name
Expand Down
42 changes: 23 additions & 19 deletions src/implant/dirac/implant.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,15 @@
(ocall js/window "setTimeout" helpers/throw-internal-error! 0))

(defn trigger-internal-error-in-promise! []
(let [delayed-promise (js/Promise.
(fn [resolve _reject]
(ocall js/window "setTimeout" resolve 0)))]
(let [delayed-promise (js/Promise. #(ocall js/window "setTimeout" % 0))]
(ocall delayed-promise "then" #(throw (ex-info "fake async error in promise" {:val %})))
true))

(defn trigger-internal-error-as-error-log! []
; timeout is needed for testing from console
; see http://stackoverflow.com/a/27257742/84283
(ocall js/window "setTimeout" #(error "a fake error log" 1 2 3) 0))

(defn report-namespaces-cache-cool-down! []
(post-feedback! "namespacesCache is cool now")
(.pause *namespaces-cache-debouncer*))
Expand All @@ -118,22 +121,23 @@

; !!! don't forget to update externs.js when touching this !!!
(def dirac-api-to-export
{"feedback" post-feedback!
"initConsole" init-console!
"initRepl" init-repl!
"notifyPanelSwitch" notify-panel-switch
"adoptPrompt" adopt-prompt!
"sendEvalRequest" send-eval-request!
"getVersion" get-version
"getRuntimeTag" get-runtime-tag
"parseNsFromSource" parse-ns-from-source
"nsToRelpath" ns-to-relpath
"triggerInternalError" trigger-internal-error!
"triggerInternalErrorInPromise" trigger-internal-error-in-promise!
"getFunctionName" get-function-name
"getFullFunctionName" get-full-function-name
"getReplSpecialsAsync" get-repl-specials-async
"reportNamespacesCacheMutation" report-namespaces-cache-mutation!})
{"feedback" post-feedback!
"initConsole" init-console!
"initRepl" init-repl!
"notifyPanelSwitch" notify-panel-switch
"adoptPrompt" adopt-prompt!
"sendEvalRequest" send-eval-request!
"getVersion" get-version
"getRuntimeTag" get-runtime-tag
"parseNsFromSource" parse-ns-from-source
"nsToRelpath" ns-to-relpath
"triggerInternalError" trigger-internal-error!
"triggerInternalErrorInPromise" trigger-internal-error-in-promise!
"triggerInternalErrorAsErrorLog" trigger-internal-error-as-error-log!
"getFunctionName" get-function-name
"getFullFunctionName" get-full-function-name
"getReplSpecialsAsync" get-repl-specials-async
"reportNamespacesCacheMutation" report-namespaces-cache-mutation!})

(defn enhance-dirac-object! [dirac]
(doseq [[name fn] dirac-api-to-export]
Expand Down
3 changes: 2 additions & 1 deletion src/implant/dirac/implant/automation.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@
{:pre [(or (nil? delay) (number? delay))]}
(let [fn-name (case kind
:unhandled-exception "triggerInternalError"
:unhandled-exception-in-promise "triggerInternalErrorInPromise")
:unhandled-exception-in-promise "triggerInternalErrorInPromise"
:error-log "triggerInternalErrorAsErrorLog")
trigger-fn #(ocall (oget js/window "dirac") fn-name)]
(trigger-fn-and-wait! trigger-fn delay)))

Expand Down
27 changes: 23 additions & 4 deletions src/implant/dirac/implant/reporter.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
; -- handling global exceptions ---------------------------------------------------------------------------------------------

(defn devtools-exception-handler! [_message _source _lineno _colno e]
(let [text (str "Internal Dirac Error: DevTools code has thrown an unhandled exception\n" (utils/format-error e))]
(let [body (utils/format-error e)
text (str "Internal Dirac Error: DevTools code has thrown an unhandled exception\n" body)]
(ocall (oget js/window "dirac") "addConsoleMessageToMainTarget" "error" text)
(feedback/post! text)
false))
Expand All @@ -19,16 +20,34 @@

(defn devtools-unhandled-rejection-handler! [event]
(let [reason (oget event "reason")
text (str "Internal Dirac Error: DevTools code has thrown an unhandled rejection (in promise)\n"
(utils/format-error reason))]
body (utils/format-error reason)
text (str "Internal Dirac Error: DevTools code has thrown an unhandled rejection (in promise)\n" body)]
(ocall (oget js/window "dirac") "addConsoleMessageToMainTarget" "error" text)
(feedback/post! text)))

(defn register-unhandled-rejection-handler! []
(.addEventListener js/window "unhandledrejection" devtools-unhandled-rejection-handler!))

; -- handling console.error -------------------------------------------------------------------------------------------------

(defonce ^:dynamic *original-console-error-fn* nil)

(defn console-error-fn [& args]
(assert *original-console-error-fn*)
(let [result (.apply *original-console-error-fn* js/console (into-array args))]
(let [body (pr-str args)
text (str "Internal Dirac Error: an error was logged into the internal DevTools console\n" body)]
(ocall (oget js/window "dirac") "addConsoleMessageToMainTarget" "error" text)
(feedback/post! text))
result))

(defn register-console-error-handler! []
(set! *original-console-error-fn* (oget js/console "error"))
(oset js/console ["error"] console-error-fn))

; -- installation -----------------------------------------------------------------------------------------------------------

(defn install! []
(register-global-exception-handler!)
(register-unhandled-rejection-handler!))
(register-unhandled-rejection-handler!)
(register-console-error-handler!))
2 changes: 1 addition & 1 deletion src/shared/dirac/utils.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@
(defn extract-line [s n]
(-> s
(cuerdas/lines)
(nth n)))
(nth n nil)))

(defn convert-blob-to-string [blob]
(let [channel (chan)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,10 @@
(is (= second-line "Error: fake async error in promise"))
(is (> (utils/line-count error-content) 4)))) ; assume it contains some stack trace
(testing "DevTools console.error logs should be presented in target console as Internal Dirac Error"
; TBD
))))
(<!* a/trigger-internal-error-as-error-log!)
(let [error-content (<!* a/scrape :last-log-item-content "error")
first-line (utils/extract-first-line error-content)
second-line (utils/extract-line error-content 1)]
(is (= first-line "Internal Dirac Error: an error was logged into the internal DevTools console"))
(is (= second-line "(\"a fake error log\" 1 2 3)"))
(is (= (utils/line-count error-content) 2)))))))
7 changes: 6 additions & 1 deletion test/browser/transcripts/expected/suite01-error-feedback.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,14 @@ devtools #1 Internal Dirac Error: DevTools code has thrown an unhandled rej
Error: fake async error in promise
<elided trace>
automate #1 scrape [:last-log-item-content "error"]
automate #1 trigger-internal-error-as-error-log!
devtools #1 Internal Dirac Error: an error was logged into the internal DevTools console
("a fake error log" 1 2 3)
<elided trace>
automate #1 scrape [:last-log-item-content "error"]
automate #1 close-devtools!
extension handling command: close-dirac-devtools
extension unregister devtools #1
automate close-tab-with-scenario! ["scenario-tab#1"]
summary Automated 9 actions with 0 check-points containing 6 assertions.
summary Automated 11 actions with 0 check-points containing 9 assertions.
0 failures, 0 errors.

0 comments on commit d853110

Please sign in to comment.