Skip to content

Commit

Permalink
Add tests, disable telemetry in reporter
Browse files Browse the repository at this point in the history
  • Loading branch information
rochala committed Mar 27, 2024
1 parent a9d3d2d commit ebd43f7
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,8 @@ private[meta] class TelemetryClient(

private val sendErrorReport0 =
new TelemetryRequest(sendErrorReportEndpoint, logger)
private val sendCrashReport0 =
new TelemetryRequest(sendCrashReportEndpoint, logger)

def sendErrorReport(report: telemetry.ErrorReport): Unit =
if (telemetryLevel().enabled) sendErrorReport0(report)

def sendCrashReport(report: telemetry.CrashReport): Unit =
if (telemetryLevel().enabled) sendCrashReport0(report)

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import scala.meta.pc.Report
import scala.meta.pc.ReportContext
import scala.meta.pc.Reporter
import scala.meta.pc.TimestampedFile
import scala.meta.internal.metals.EmptyReporter

object TelemetryReportContext {
case class Sanitizers(
Expand Down Expand Up @@ -54,10 +55,16 @@ class TelemetryReportContext(
)(implicit ec: ExecutionContext)
extends ReportContext {

val telemetryLevel0 = telemetryLevel()

// Don't send reports with fragile user data - sources etc
override lazy val unsanitized: Reporter = reporter("unsanitized")
override lazy val incognito: Reporter = reporter("incognito")
override lazy val bloop: Reporter = reporter("bloop")
override lazy val unsanitized: Reporter =
if (telemetryLevel0 == TelemetryLevel.Full) reporter("incognito")
else EmptyReporter
override lazy val incognito: Reporter =
if (telemetryLevel0.enabled) reporter("incognito") else EmptyReporter
override lazy val bloop: Reporter =
if (telemetryLevel0.enabled) reporter("bloop") else EmptyReporter

private val client = new TelemetryClient(
config = telemetryClientConfig,
Expand All @@ -68,7 +75,6 @@ class TelemetryReportContext(
private def reporter(name: String) = new TelemetryReporter(
name = name,
client = client,
telemetryLevel = telemetryLevel,
reporterContext = reporterContext,
sanitizers = sanitizers,
logger = logger,
Expand All @@ -78,7 +84,6 @@ class TelemetryReportContext(
private class TelemetryReporter(
override val name: String,
client: TelemetryClient,
telemetryLevel: () => TelemetryLevel,
reporterContext: () => telemetry.ReporterContext,
sanitizers: TelemetryReportContext.Sanitizers,
logger: LoggerAccess,
Expand Down Expand Up @@ -114,16 +119,14 @@ private class TelemetryReporter(
unsanitizedReport: Report,
ifVerbose: Boolean,
): ju.Optional[Path] = {
if (telemetryLevel() == TelemetryLevel.Full) {
val report = createSanitizedReport(unsanitizedReport)
if (report.text.isDefined || report.error.isDefined)
client.sendErrorReport(report)
else
logger.info(
"Skipped reporting remotely unmeaningful report, no context or error, reportId=" +
unsanitizedReport.id.orElse("null")
)
}
val report = createSanitizedReport(unsanitizedReport)
if (report.text.isDefined || report.error.isDefined)
client.sendErrorReport(report)
else
logger.info(
"Skipped reporting remotely unmeaningful report, no context or error, reportId=" +
unsanitizedReport.id.orElse("null")
)
ju.Optional.empty()
}
}
26 changes: 0 additions & 26 deletions metals/src/main/scala/scala/meta/metals/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ import scala.meta.internal.metals.ScalaVersions
import scala.meta.internal.metals.Trace
import scala.meta.internal.metals.clients.language.MetalsLanguageClient
import scala.meta.internal.metals.logging.MetalsLogger
import scala.meta.internal.telemetry.CrashReport
import scala.meta.internal.telemetry.ExceptionSummary
import scala.meta.internal.telemetry.TelemetryClient

import org.eclipse.lsp4j.jsonrpc.Launcher

Expand Down Expand Up @@ -66,7 +63,6 @@ object Main {
launcher.startListening().get()
} catch {
case NonFatal(e) =>
trySendCrashReport(e, server, ec)
e.printStackTrace(systemOut)
sys.exit(1)
} finally {
Expand All @@ -77,26 +73,4 @@ object Main {
sys.exit(0)
}
}

private def trySendCrashReport(
error: Throwable,
server: MetalsLanguageServer,
ec: ExecutionContext,
): Unit = try {
val telemetryLevel = server.getTelemetryLevel()
if (telemetryLevel.enabled) {
val telemetry = new TelemetryClient(() => telemetryLevel)(ec)
telemetry.sendCrashReport(
CrashReport(
error = ExceptionSummary.from(error, identity),
componentName = this.getClass().getName(),
componentVersion = Some(BuildInfo.metalsVersion),
)
)
}
} catch {
case err: Throwable =>
System.err.println(s"Failed to send crash report, $err")
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ object StdReportContext {
}

/**
* Fan-out report context delegating reporting to all underlyin reporters of given type.
* Fan-out report context delegating reporting to all underlying reporters of given type.
*/
class MirroredReportContext(primary: ReportContext, auxilary: ReportContext*)
extends ReportContext {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,8 @@ object TelemetryService {
"POST",
"/v1/telemetry/sendErrorReport",
)
val sendCrashReportEndpoint = new FireAndForgetEndpoint[CrashReport](
"POST",
"/v1/telemetry/sendCrashReport",
)
}

trait TelemetryService {
def sendErrorReport(errorReport: ErrorReport): Unit
def sendCrashReport(crashReport: CrashReport): Unit
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class TelemetryReporterSuite extends BaseSuite {
def simpleReport(id: String): Report = StandardReport(
name = "name",
text = "text",
shortSummary = "sumamry",
shortSummary = "summmary",
path = None,
id = Some(id),
error = Some(new RuntimeException("A", new NullPointerException())),
Expand Down Expand Up @@ -80,13 +80,65 @@ class TelemetryReporterSuite extends BaseSuite {
} {
val createdReport = simpleReport(reporterCtx.toString())
reporter.incognito.create(createdReport)
Thread.sleep(5000) // wait for the server to receive the event
Thread.sleep(1000) // wait for the server to receive the event
val received = ctx.errors.filter(_.id == createdReport.id.asScala)
assert(received.nonEmpty, "Not received matching id")
assert(received.size == 1, "Found more then 1 received event")
}
} finally server.stop()
}

locally {
implicit val ctx = new MockTelemetryServer.Context()
val server = MockTelemetryServer("127.0.0.1", 8081)

def testCase(level: metals.TelemetryLevel, expected: Set[String]): Unit =
test(
s"Telemetry level: ${level} sends telemetry for ${expected.mkString("(", ", ", ")")}"
) {
ctx.errors.clear()

try {
server.start()
val serverEndpoint = MockTelemetryServer.address(server)
for {
reporterCtx <- Seq(
SampleReports.metalsLspReport(),
SampleReports.scalaPresentationCompilerReport(),
).map(_.reporterContext)
reporter = new TelemetryReportContext(
telemetryClientConfig = TelemetryClient.Config.default
.copy(serverHost = serverEndpoint),
telemetryLevel = () => level,
reporterContext = () => reporterCtx,
sanitizers = new TelemetryReportContext.Sanitizers(
None,
Some(metals.ScalametaSourceCodeTransformer),
),
)
} {

reporter.incognito.create(simpleReport("incognito"))
reporter.bloop.create(simpleReport("bloop"))
reporter.unsanitized.create(simpleReport("unsanitized"))

def received = ctx.errors.map(_.id.get).toSet
Thread.sleep(1000)
assertEquals(received, expected)
}
} finally {
server.stop()
}
}

testCase(metals.TelemetryLevel.Off, Set())
testCase(metals.TelemetryLevel.Anonymous, Set("incognito", "bloop"))
testCase(
metals.TelemetryLevel.Full,
Set("incognito", "bloop", "unsanitized"),
)
}

}

object MockTelemetryServer {
Expand All @@ -97,8 +149,7 @@ object MockTelemetryServer {
import io.undertow.util.Headers

case class Context(
errors: mutable.ListBuffer[ErrorReport] = mutable.ListBuffer.empty,
crashes: mutable.ListBuffer[CrashReport] = mutable.ListBuffer.empty,
errors: mutable.ListBuffer[ErrorReport] = mutable.ListBuffer.empty
)

def apply(
Expand All @@ -112,10 +163,6 @@ object MockTelemetryServer {
TelemetryService.sendErrorReportEndpoint,
_.errors,
)
.withEndpoint(
TelemetryService.sendCrashReportEndpoint,
_.crashes,
)
Undertow.builder
.addHttpListener(port, host)
.setHandler(baseHandler)
Expand Down

0 comments on commit ebd43f7

Please sign in to comment.