Skip to content

Commit 3ca228d

Browse files
committed
ability to run probe via plugin
1 parent e7d003b commit 3ca228d

File tree

4 files changed

+149
-11
lines changed

4 files changed

+149
-11
lines changed

control/src/main/kotlin/spp/probe/ProbeConfiguration.kt

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,39 @@ object ProbeConfiguration {
1616
init {
1717
var localFile = File("spp-probe.yml")
1818
try {
19-
//working directory
19+
//working directory?
2020
val mapper = ObjectMapper(YAMLFactory())
2121
if (localFile.exists()) {
2222
rawProperties = mapper.readValue(FileInputStream(localFile), MutableMap::class.java)
2323
as Map<String, Map<String, Any>>?
2424
}
25-
//ran through intellij
26-
localFile = File(
27-
File(
28-
ProbeConfiguration::class.java.protectionDomain.codeSource.location.toURI()
29-
).parent, "spp-probe.yml"
30-
)
31-
if (localFile.exists()) {
32-
rawProperties = mapper.readValue(FileInputStream(localFile), MutableMap::class.java)
33-
as Map<String, Map<String, Any>>?
25+
if (ProbeConfiguration::class.java.protectionDomain.codeSource.location == null) {
26+
//ran through SkyWalking
27+
localFile = File(
28+
File(
29+
Class.forName(
30+
"org.apache.skywalking.apm.agent.core.plugin.loader.AgentClassLoader"
31+
).protectionDomain.codeSource.location.file
32+
).parentFile, "plugins" + File.separatorChar + "spp-probe.yml"
33+
)
34+
if (localFile.exists()) {
35+
rawProperties = mapper.readValue(FileInputStream(localFile), MutableMap::class.java)
36+
as Map<String, Map<String, Any>>?
37+
}
38+
} else {
39+
//ran through intellij?
40+
localFile = File(
41+
File(
42+
ProbeConfiguration::class.java.protectionDomain.codeSource.location.toURI()
43+
).parent, "spp-probe.yml"
44+
)
45+
if (localFile.exists()) {
46+
rawProperties = mapper.readValue(FileInputStream(localFile), MutableMap::class.java)
47+
as Map<String, Map<String, Any>>?
48+
}
3449
}
35-
//inside jar
50+
51+
//inside jar?
3652
if (rawProperties == null) {
3753
rawProperties = mapper.readValue(
3854
ProbeConfiguration::class.java.getResourceAsStream("/spp-probe.yml"), MutableMap::class.java

control/src/main/kotlin/spp/probe/SourceProbe.kt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,41 @@ object SourceProbe {
5353
val isAgentInitialized: Boolean
5454
get() = instrumentation != null
5555

56+
@JvmStatic
57+
fun bootAsPlugin(inst: Instrumentation) {
58+
if (ProbeConfiguration.isNotQuite) println("SourceProbe initiated")
59+
60+
//todo: pipe data if in debug mode
61+
System.setProperty("vertx.logger-delegate-factory-class-name", NopLogDelegateFactory::class.java.canonicalName)
62+
InternalLoggerFactory.setDefaultFactory(object : InternalLoggerFactory() {
63+
private val nopInternalLogger = NopInternalLogger()
64+
override fun newInstance(name: String): InternalLogger {
65+
return nopInternalLogger
66+
}
67+
})
68+
instrumentation = inst
69+
vertx = Vertx.vertx()
70+
71+
configureAgent()
72+
connectToPlatform()
73+
try {
74+
val agentClassLoader = Class.forName(
75+
"org.apache.skywalking.apm.agent.core.plugin.loader.AgentClassLoader"
76+
).getMethod("getDefault").invoke(null) as java.lang.ClassLoader
77+
val sizeCappedClass = Class.forName(
78+
"spp.probe.services.common.serialize.SizeCappedTypeAdapterFactory", true, agentClassLoader
79+
)
80+
sizeCappedClass.getMethod("setInstrumentation", Instrumentation::class.java)
81+
.invoke(null, instrumentation)
82+
sizeCappedClass.getMethod("setMaxMemorySize", Long::class.javaPrimitiveType)
83+
.invoke(null, 1024L * 1024L) //1MB
84+
} catch (e: Exception) {
85+
e.printStackTrace()
86+
throw RuntimeException(e)
87+
}
88+
vertx!!.deployVerticle(LiveInstrumentRemote().also { instrumentRemote = it })
89+
}
90+
5691
@JvmStatic
5792
fun premain(args: String?, inst: Instrumentation) {
5893
if (ProbeConfiguration.isNotQuite) println("SourceProbe initiated")
@@ -67,6 +102,7 @@ object SourceProbe {
67102
})
68103
instrumentation = inst
69104
vertx = Vertx.vertx()
105+
70106
unzipAgent(BUILD.getString("apache_skywalking_version"))
71107
addAgentToClassLoader()
72108
configureAgent()
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package spp.probe
2+
3+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint
4+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint
5+
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine
6+
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch
7+
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch
8+
import java.lang.instrument.ClassFileTransformer
9+
import java.lang.instrument.Instrumentation
10+
import java.lang.reflect.Field
11+
import java.lang.reflect.Modifier
12+
import java.lang.reflect.Proxy
13+
import java.util.concurrent.atomic.AtomicBoolean
14+
15+
/**
16+
* Borrows Instrumentation from SkyWalking/Byte Buddy and boots SourceProbe.
17+
*/
18+
class SourceProbePluginDefine : ClassInstanceMethodsEnhancePluginDefine() {
19+
20+
override fun enhanceClass(): ClassMatch {
21+
val defaultClass = Class.forName(
22+
"org.apache.skywalking.apm.dependencies.net.bytebuddy.agent.builder.AgentBuilder\$Default"
23+
)
24+
val dispatcherField = defaultClass.getDeclaredField("DISPATCHER")
25+
makeAccessible(dispatcherField)
26+
val realDispatcher = dispatcherField.get(null)
27+
dispatcherField.set(null, null)
28+
29+
val dispatcherClass = Class.forName(
30+
"org.apache.skywalking.apm.dependencies.net.bytebuddy.agent.builder.AgentBuilder\$Default\$Dispatcher"
31+
)
32+
val addTransformerMethod = dispatcherClass.getDeclaredMethod(
33+
"addTransformer",
34+
Instrumentation::class.java, ClassFileTransformer::class.java, Boolean::class.java
35+
)
36+
val setNativeMethodPrefixMethod = dispatcherClass.getDeclaredMethod(
37+
"setNativeMethodPrefix",
38+
Instrumentation::class.java, ClassFileTransformer::class.java, String::class.java
39+
)
40+
val isNativeMethodPrefixSupportedMethod = dispatcherClass.getDeclaredMethod(
41+
"isNativeMethodPrefixSupported", Instrumentation::class.java
42+
)
43+
44+
val probeStarted = AtomicBoolean()
45+
val proxyDispatcher = Proxy.newProxyInstance(
46+
dispatcherClass.classLoader,
47+
arrayOf(dispatcherClass)
48+
) { _, method, args ->
49+
return@newProxyInstance when (method.name) {
50+
"addTransformer" -> {
51+
if (probeStarted.compareAndSet(false, true)) {
52+
SourceProbe.bootAsPlugin(args?.get(0) as Instrumentation)
53+
}
54+
addTransformerMethod.invoke(realDispatcher, args[0], args[1], args[2])
55+
}
56+
"setNativeMethodPrefix" -> {
57+
setNativeMethodPrefixMethod.invoke(realDispatcher, args[0], args[1], args[2])
58+
}
59+
"isNativeMethodPrefixSupported" -> {
60+
isNativeMethodPrefixSupportedMethod.invoke(realDispatcher, args[0])
61+
}
62+
else -> throw IllegalStateException("Unknown method: ${method.name}")
63+
}
64+
}
65+
dispatcherField.set(null, proxyDispatcher)
66+
67+
return NameMatch.byName("") //ignore
68+
}
69+
70+
@Throws(Exception::class)
71+
fun makeAccessible(field: Field) {
72+
field.isAccessible = true
73+
val modifiersField: Field = Field::class.java.getDeclaredField("modifiers")
74+
modifiersField.isAccessible = true
75+
modifiersField.setInt(field, field.modifiers and Modifier.FINAL.inv())
76+
}
77+
78+
override fun getConstructorsInterceptPoints(): Array<ConstructorInterceptPoint> {
79+
return emptyArray() //ignore
80+
}
81+
82+
override fun getInstanceMethodsInterceptPoints(): Array<InstanceMethodsInterceptPoint> {
83+
return emptyArray() //ignore
84+
}
85+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
spp-probe=spp.probe.SourceProbePluginDefine

0 commit comments

Comments
 (0)