Skip to content

Commit 4958198

Browse files
authored
Merge pull request #7 from sourceplusplus/sub-events
Sub events
2 parents 84afd4b + 2dde400 commit 4958198

File tree

9 files changed

+700
-1224
lines changed

9 files changed

+700
-1224
lines changed

build.gradle.kts

+6-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ version = cliVersion
2626

2727
repositories {
2828
mavenCentral()
29-
jcenter()
3029
maven(url = "https://jitpack.io") { name = "jitpack" }
3130
}
3231

@@ -37,7 +36,11 @@ dependencies {
3736

3837
implementation("com.github.sourceplusplus.protocol:protocol:$protocolVersion")
3938

39+
implementation("org.slf4j:slf4j-api:1.7.32")
40+
implementation("org.slf4j:slf4j-nop:1.7.32")
4041
implementation("io.vertx:vertx-core:$vertxVersion")
42+
implementation("io.vertx:vertx-tcp-eventbus-bridge:$vertxVersion")
43+
implementation("io.vertx:vertx-lang-kotlin-coroutines:$vertxVersion")
4144
implementation("org.apache.commons:commons-lang3:$commonsLang3Version")
4245
implementation("com.github.ajalt.clikt:clikt:$cliktVersion")
4346
implementation("org.bouncycastle:bcprov-jdk15on:$bouncycastleVersion")
@@ -49,6 +52,7 @@ dependencies {
4952
implementation("eu.geekplace.javapinning:java-pinning-core:1.2.0")
5053

5154
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jacksonVersion")
55+
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.3.1")
5256

5357
testImplementation("org.junit.jupiter:junit-jupiter-engine:$jupiterVersion")
5458
}
@@ -75,7 +79,7 @@ tasks.create("createProperties") {
7579
tasks["processResources"].dependsOn("createProperties")
7680

7781
graal {
78-
//graalVersion(graalVersion.toString())
82+
graalVersion(project.properties["graalVersion"] as String)
7983
mainClass("spp.cli.Main")
8084
outputName("spp-cli")
8185
option("-H:+PrintClassInitialization")
@@ -100,7 +104,6 @@ tasks.getByName("build").dependsOn("shadowJar")
100104

101105
configurations.runtimeClasspath {
102106
exclude("ch.qos.logback", "logback-classic")
103-
exclude("org.slf4j", "slf4j-api")
104107
}
105108

106109
tasks.getByName<Test>("test") {

gradle.properties

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ kotlin.code.style=official
33
cliGroup = com.sourceplusplus
44
cliVersion = 0.2.2
55

6-
protocolVersion=0.2.2
6+
protocolVersion=0.2.3
77

88
#SkyWalking 8.9.0-compatible
99
vertxVersion = 4.0.2
1010

11-
graalVersion = 20.2.0
11+
graalVersion = 21.3.0
1212
jacksonVersion = 2.12.5
1313
apolloVersion = 2.5.11
1414
commonsLang3Version = 3.12.0

src/main/kotlin/spp/cli/Main.kt

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ object Main {
6464
RemoveInstrument(),
6565
RemoveInstruments(),
6666
ClearInstruments(),
67+
SubscribeEvents(),
6768
//etc
6869
Version()
6970
).main(args)

src/main/kotlin/spp/cli/PlatformCLI.kt

+27-15
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,18 @@ package spp.cli
33
import com.apollographql.apollo.ApolloClient
44
import com.auth0.jwt.JWT
55
import com.auth0.jwt.algorithms.Algorithm
6+
import com.fasterxml.jackson.databind.module.SimpleModule
67
import com.github.ajalt.clikt.core.CliktCommand
78
import com.github.ajalt.clikt.parameters.options.default
89
import com.github.ajalt.clikt.parameters.options.flag
910
import com.github.ajalt.clikt.parameters.options.option
1011
import com.github.ajalt.clikt.parameters.types.file
1112
import eu.geekplace.javapinning.JavaPinning
13+
import io.vertx.core.json.jackson.DatabindCodec
14+
import kotlinx.datetime.Clock
15+
import kotlinx.datetime.DateTimeUnit
16+
import kotlinx.datetime.Instant
17+
import kotlinx.datetime.plus
1218
import okhttp3.OkHttpClient
1319
import okhttp3.Request
1420
import org.bouncycastle.cert.X509CertificateHolder
@@ -18,22 +24,21 @@ import org.bouncycastle.openssl.PEMKeyPair
1824
import org.bouncycastle.openssl.PEMParser
1925
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter
2026
import org.bouncycastle.util.encoders.Hex
27+
import spp.protocol.util.KSerializers
2128
import java.io.File
2229
import java.io.StringReader
2330
import java.security.SecureRandom
2431
import java.security.cert.X509Certificate
2532
import java.security.interfaces.RSAPrivateKey
2633
import java.security.interfaces.RSAPublicKey
27-
import java.time.Instant
28-
import java.time.temporal.ChronoUnit
2934
import javax.net.ssl.SSLContext
3035
import javax.net.ssl.TrustManager
3136
import javax.net.ssl.X509TrustManager
3237

3338
object PlatformCLI : CliktCommand(name = "spp-cli", allowMultipleSubcommands = true) {
3439

3540
val verbose by option("-v", "--verbose", help = "Enable verbose mode").flag()
36-
private val platformHost: String by option("-p", "--platform", help = "Source++ platform host")
41+
val platformHost: String by option("-p", "--platform", help = "Source++ platform host")
3742
.default(
3843
(if (System.getenv("SPP_DISABLE_TLS") != "true") "https://" else "http://")
3944
+ (System.getenv("SPP_PLATFORM_HOST") ?: "localhost") + ":5445"
@@ -44,8 +49,24 @@ object PlatformCLI : CliktCommand(name = "spp-cli", allowMultipleSubcommands = t
4449
.default(File("config/spp-platform.key"))
4550
private val accessToken by option("-a", "--access-token", help = "Developer access token")
4651
val apolloClient: ApolloClient by lazy { connectToPlatform() }
52+
val certFingerprint: String? by lazy {
53+
if (platformCertificate.exists()) {
54+
val crtFileData = platformCertificate.readText()
55+
val crtParser = PEMParser(StringReader(crtFileData))
56+
val crtHolder = crtParser.readObject() as X509CertificateHolder
57+
val certificate = JcaX509CertificateConverter().getCertificate(crtHolder)!!
58+
fingerprint(certificate)
59+
} else {
60+
null
61+
}
62+
}
4763

48-
override fun run() = Unit
64+
override fun run() {
65+
val module = SimpleModule()
66+
module.addSerializer(Instant::class.java, KSerializers.KotlinInstantSerializer())
67+
module.addDeserializer(Instant::class.java, KSerializers.KotlinInstantDeserializer())
68+
DatabindCodec.mapper().registerModule(module)
69+
}
4970

5071
private fun connectToPlatform(): ApolloClient {
5172
val serverUrl = if (platformHost.startsWith("http")) {
@@ -54,15 +75,6 @@ object PlatformCLI : CliktCommand(name = "spp-cli", allowMultipleSubcommands = t
5475
"https://$platformHost"
5576
}
5677

57-
var certFingerprint: String? = null
58-
if (platformCertificate.exists()) {
59-
val crtFileData = platformCertificate.readText()
60-
val crtParser = PEMParser(StringReader(crtFileData))
61-
val crtHolder = crtParser.readObject() as X509CertificateHolder
62-
val certificate = JcaX509CertificateConverter().getCertificate(crtHolder)!!
63-
certFingerprint = fingerprint(certificate)
64-
}
65-
6678
val httpClient = if (certFingerprint != null) {
6779
OkHttpClient().newBuilder()
6880
.hostnameVerifier { _, _ -> true }
@@ -97,8 +109,8 @@ object PlatformCLI : CliktCommand(name = "spp-cli", allowMultipleSubcommands = t
97109
jwtToken = JWT.create()
98110
.withIssuer("cli")
99111
.withClaim("developer_id", "system") //users with key are automatically considered system
100-
.withClaim("created_at", Instant.now().toEpochMilli())
101-
.withClaim("expires_at", Instant.now().plus(365, ChronoUnit.DAYS).toEpochMilli())
112+
.withClaim("created_at", Clock.System.now().toEpochMilliseconds())
113+
.withClaim("expires_at", Clock.System.now().plus(8760, DateTimeUnit.HOUR).toEpochMilliseconds())
102114
.sign(algorithm)
103115
} else {
104116
val tokenUri = "$serverUrl/api/new-token?access_token=$accessToken"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
package spp.cli.commands.instrument
2+
3+
import com.github.ajalt.clikt.core.CliktCommand
4+
import com.github.ajalt.clikt.parameters.arguments.argument
5+
import com.github.ajalt.clikt.parameters.arguments.multiple
6+
import com.github.ajalt.clikt.parameters.options.flag
7+
import com.github.ajalt.clikt.parameters.options.option
8+
import eu.geekplace.javapinning.JavaPinning
9+
import eu.geekplace.javapinning.pin.Pin
10+
import io.vertx.core.Vertx
11+
import io.vertx.core.json.Json
12+
import io.vertx.core.json.JsonObject
13+
import io.vertx.core.net.NetClientOptions
14+
import io.vertx.core.net.TrustOptions
15+
import io.vertx.ext.bridge.BridgeEventType
16+
import io.vertx.ext.eventbus.bridge.tcp.impl.protocol.FrameHelper
17+
import io.vertx.ext.eventbus.bridge.tcp.impl.protocol.FrameParser
18+
import io.vertx.kotlin.coroutines.await
19+
import kotlinx.coroutines.runBlocking
20+
import spp.cli.PlatformCLI
21+
import spp.protocol.SourceMarkerServices
22+
import spp.protocol.extend.TCPServiceFrameParser
23+
import spp.protocol.instrument.LiveInstrumentEvent
24+
import spp.protocol.instrument.LiveInstrumentEventType
25+
import spp.protocol.instrument.breakpoint.event.LiveBreakpointHit
26+
import spp.protocol.instrument.breakpoint.event.LiveBreakpointRemoved
27+
import spp.protocol.instrument.log.event.LiveLogHit
28+
import spp.protocol.instrument.log.event.LiveLogRemoved
29+
30+
class SubscribeEvents : CliktCommand(
31+
help = "Listens for and outputs live events. Subscribes to all events by default"
32+
) {
33+
34+
val instrumentIds by argument(
35+
name = "Instrument IDs",
36+
help = "Capture events from specific live instruments"
37+
).multiple()
38+
39+
val includeBreakpoints by option("--breakpoints", "-b", help = "Include live breakpoint events")
40+
.flag(default = false)
41+
val includeLogs by option("--logs", "-l", help = "Include live log events")
42+
.flag(default = false)
43+
val includeMeters by option("--meters", "-m", help = "Include live meter events")
44+
.flag(default = false)
45+
val includeTraces by option("--traces", "-t", help = "Include live trace events")
46+
.flag(default = false)
47+
48+
override fun run() {
49+
var eventCount = 1
50+
runBlocking {
51+
val vertx = Vertx.vertx()
52+
val client = if (PlatformCLI.certFingerprint != null) {
53+
val options = NetClientOptions()
54+
.setReconnectAttempts(Int.MAX_VALUE).setReconnectInterval(5000)
55+
.setSsl(PlatformCLI.platformHost.startsWith("https"))
56+
.setTrustOptions(
57+
TrustOptions.wrap(
58+
JavaPinning.trustManagerForPins(listOf(Pin.fromString("CERTSHA256:${PlatformCLI.certFingerprint}")))
59+
)
60+
)
61+
vertx.createNetClient(options)
62+
} else {
63+
val options = NetClientOptions()
64+
.setReconnectAttempts(Int.MAX_VALUE).setReconnectInterval(5000)
65+
.setSsl(PlatformCLI.platformHost.startsWith("https"))
66+
vertx.createNetClient(options)
67+
}
68+
val socket = client.connect(
69+
5455,
70+
PlatformCLI.platformHost.substringAfter("https://").substringAfter("http://")
71+
.substringBefore(":")
72+
).await()
73+
socket!!.handler(FrameParser(TCPServiceFrameParser(vertx, socket)))
74+
75+
vertx.eventBus().consumer<JsonObject>("local." + SourceMarkerServices.Provide.LIVE_INSTRUMENT_SUBSCRIBER) {
76+
val liveEvent = Json.decodeValue(it.body().toString(), LiveInstrumentEvent::class.java)
77+
78+
//todo: impl filter on platform
79+
if (instrumentIds.isNotEmpty()) {
80+
when (liveEvent.eventType) {
81+
LiveInstrumentEventType.LOG_HIT -> {
82+
val logHit = Json.decodeValue(liveEvent.data, LiveLogHit::class.java)
83+
if (logHit.logId !in instrumentIds) {
84+
return@consumer
85+
}
86+
}
87+
LiveInstrumentEventType.BREAKPOINT_HIT -> {
88+
val breakpointHit = Json.decodeValue(liveEvent.data, LiveBreakpointHit::class.java)
89+
if (breakpointHit.breakpointId !in instrumentIds) {
90+
return@consumer
91+
}
92+
}
93+
LiveInstrumentEventType.BREAKPOINT_REMOVED -> {
94+
val breakpointRemoved = Json.decodeValue(liveEvent.data, LiveBreakpointRemoved::class.java)
95+
if (breakpointRemoved.breakpointId !in instrumentIds) {
96+
return@consumer
97+
}
98+
}
99+
LiveInstrumentEventType.LOG_REMOVED -> {
100+
val logRemoved = Json.decodeValue(liveEvent.data, LiveLogRemoved::class.java)
101+
if (logRemoved.logId !in instrumentIds) {
102+
return@consumer
103+
}
104+
}
105+
else -> TODO("Unhandled event type: ${liveEvent.eventType}")
106+
}
107+
}
108+
109+
if (!includeBreakpoints && !includeLogs && !includeMeters && !includeTraces) {
110+
//listen for all events
111+
println(
112+
"\nEvent (${eventCount++}):\n" +
113+
"\tType: ${liveEvent.eventType}\n" +
114+
"\tData: ${liveEvent.data}"
115+
)
116+
} else {
117+
//todo: impl filtering on platform
118+
//listen for specific events
119+
if (includeBreakpoints && liveEvent.eventType.name.startsWith("breakpoint", true)) {
120+
println(
121+
"\nEvent (${eventCount++}):\n" +
122+
"\tType: ${liveEvent.eventType}\n" +
123+
"\tData: ${liveEvent.data}"
124+
)
125+
} else if (includeLogs && liveEvent.eventType.name.startsWith("log", true)) {
126+
println(
127+
"\nEvent (${eventCount++}):\n" +
128+
"\tType: ${liveEvent.eventType}\n" +
129+
"\tData: ${liveEvent.data}"
130+
)
131+
} else if (includeMeters && liveEvent.eventType.name.startsWith("meter", true)) {
132+
println(
133+
"\nEvent (${eventCount++}):\n" +
134+
"\tType: ${liveEvent.eventType}\n" +
135+
"\tData: ${liveEvent.data}"
136+
)
137+
} else if (includeTraces && liveEvent.eventType.name.startsWith("trace", true)) {
138+
println(
139+
"\nEvent (${eventCount++}):\n" +
140+
"\tType: ${liveEvent.eventType}\n" +
141+
"\tData: ${liveEvent.data}"
142+
)
143+
}
144+
}
145+
}
146+
147+
//register listener
148+
FrameHelper.sendFrame(
149+
BridgeEventType.REGISTER.name.toLowerCase(),
150+
SourceMarkerServices.Provide.LIVE_INSTRUMENT_SUBSCRIBER,
151+
JsonObject(),
152+
socket
153+
)
154+
println("Listening for events...")
155+
}
156+
}
157+
}
Original file line numberDiff line numberDiff line change
@@ -1 +1,33 @@
1-
[]
1+
[
2+
{
3+
"name":"java.lang.Boolean",
4+
"methods":[{"name":"getBoolean","parameterTypes":["java.lang.String"] }]}
5+
,
6+
{
7+
"name":"java.lang.ClassLoader",
8+
"methods":[
9+
{"name":"getPlatformClassLoader","parameterTypes":[] },
10+
{"name":"loadClass","parameterTypes":["java.lang.String"] }
11+
]}
12+
,
13+
{
14+
"name":"jdk.internal.loader.ClassLoaders$PlatformClassLoader"}
15+
,
16+
{
17+
"name":"org.graalvm.nativebridge.jni.JNIExceptionWrapperEntryPoints",
18+
"methods":[{"name":"getClassName","parameterTypes":["java.lang.Class"] }]}
19+
,
20+
{
21+
"name":"sun.management.VMManagementImpl",
22+
"fields":[
23+
{"name":"compTimeMonitoringSupport"},
24+
{"name":"currentThreadCpuTimeSupport"},
25+
{"name":"objectMonitorUsageSupport"},
26+
{"name":"otherThreadCpuTimeSupport"},
27+
{"name":"remoteDiagnosticCommandsSupport"},
28+
{"name":"synchronizerUsageSupport"},
29+
{"name":"threadAllocatedMemorySupport"},
30+
{"name":"threadContentionMonitoringSupport"}
31+
]}
32+
33+
]

0 commit comments

Comments
 (0)