Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom compiler crash/panic handler #731

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 108 additions & 4 deletions effekt/jvm/src/main/scala/effekt/Driver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import effekt.context.{ Context, IOModuleDB }
import kiama.output.PrettyPrinterTypes.Document
import kiama.parsing.ParseResult
import kiama.util.{ IO, Source }
import effekt.util.messages.{ BufferedMessaging, CompilerPanic, EffektError, EffektMessaging, FatalPhaseError }
import effekt.util.messages.{ BufferedMessaging, CompilerPanic, EffektError, EffektMessaging, FatalPhaseError, PlainTextError }
import effekt.util.paths.file
import effekt.util.{ AnsiColoredMessaging, MarkdownSource, getOrElseAborting }

Expand Down Expand Up @@ -90,9 +90,8 @@ trait Driver extends kiama.util.Compiler[EffektConfig, EffektError] { outer =>
case FatalPhaseError(msg) => context.report(msg)
case e @ CompilerPanic(msg) =>
context.report(msg)
JakubSchwenkbeck marked this conversation as resolved.
Show resolved Hide resolved
e.getStackTrace.foreach { line =>
context.info(" at " + line)
}
generateCrashReport(e, context, config, msg)

// when in server-mode, do not crash but report the error to avoid
// restarting the server.
case e if config.server() =>
Expand All @@ -108,6 +107,111 @@ trait Driver extends kiama.util.Compiler[EffektConfig, EffektError] { outer =>
afterCompilation(source, config)(context)
}

def generateCrashReport(e: Throwable, context: Context, config: EffektConfig, msg:effekt. util. messages. EffektError): Unit = {
import java.nio.file.{Files, Paths}
import java.nio.charset.StandardCharsets

// Capture general information
val errorMessage = msg match {
case PlainTextError(content, _, _) => content
case _ => msg
}

val effektVersion = effekt.util.Version.effektVersion
val osInfoName = System.getProperty("os.name")
val osInfoArch = System.getProperty("os.arch")
val osInfoVersion = System.getProperty("os.version")

val javaInfoVersion = System.getProperty("java.version")
val javaInfoVendor = System.getProperty("java.vendor")
val javaInfoRuntime = System.getProperty("java.runtime.name")

val errorReport = "The compiler unexpectedly panicked. This is a compiler bug.\nPlease report it:"
val issueLink = "https://github.com/effekt-lang/effekt/issues/new?labels=bug"

// Write stacktrace
val stringWriter = new java.io.StringWriter()
e.printStackTrace(new java.io.PrintWriter(stringWriter))
val stackTrace = stringWriter.toString

// Collect backend details (if applicable)
val backendInfoName = config.backend() match {
case Backend(name, _, _) => name
case null => "Backend-specific info Name not retrievable"
}

// Collect arguments passed to the compiler
val argsMarkdown = config.args.mkString("\n", "\n", "\n")

// Construct the report content
val reportContent =
s"""|# Effekt Compiler Crash Report
|
|**ERROR** : $errorMessage
|
|$errorReport [Submit an issue]($issueLink)
|
|### Compiler Information
|Effekt Version: $effektVersion \n
|Backend: $backendInfoName
|
|### System Information
|Operating System: $osInfoName \n Arch: $osInfoArch \n Version: $osInfoVersion
|
|JVM Version: $javaInfoVersion ($javaInfoVendor, $javaInfoRuntime)
|
|### Full Stack Trace
|```
|$stackTrace
|```
|
|### Arguments Passed to the Compiler
|```
|$argsMarkdown
|```
|""".stripMargin

// Write the report to a Markdown file
val outputPath = Paths.get(config.outputPath().getAbsolutePath)
val outputFile = outputPath.resolve("crash-report.md")
try {
Files.createDirectories(outputPath.getParent)
Files.write(outputFile, reportContent.getBytes(StandardCharsets.UTF_8))
} catch {
case ex: Exception =>
context.info("Failed to save crash report to file: " + ex.getMessage)
}

// Terimnal output with reference to .md report
val report =
s"""|=== Effekt Compiler Crash Report ===
|
|[Error] $errorMessage
|
|The compiler unexpectedly panicked. This is a compiler bug.
|Please report it: $issueLink
|
|Effekt Version: $effektVersion\n
|Backend used: $backendInfoName
|
|A detailed crash report has been written to:
|${outputPath.toAbsolutePath}
|
|Operating System: $osInfoName
|
|JVM Version: $javaInfoVersion
|
|Full Stack Trace:
|$stackTrace
|
|Arguments passed to the compiler:
|$argsMarkdown
|""".stripMargin

// Print the report to console
context.info(report)
}

/**
* Outputs the timing information captured in [[effekt.util.Timers]] by [[effekt.context.Context]]. Either a JSON file
* is written to disk or a plain text message is written to stdout.
Expand Down
Loading