Skip to content

Commit e5fb77f

Browse files
authored
Merge pull request #42 from sourceplusplus/issue-39
Issue 39
2 parents ad8d35b + 7740740 commit e5fb77f

File tree

10 files changed

+140
-359
lines changed

10 files changed

+140
-359
lines changed

.ext/gson-2.8.6-SNAPSHOT.jar

244 KB
Binary file not shown.

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ import java.util.zip.ZipInputStream
5050

5151
object SourceProbe {
5252

53-
private val BUILD = ResourceBundle.getBundle("build")
53+
private val BUILD = ResourceBundle.getBundle("probe_build")
5454
private var PROBE_DIRECTORY = File(
5555
if (System.getProperty("os.name").lowercase().startsWith("mac"))
5656
"/tmp" else System.getProperty("java.io.tmpdir"), "spp-probe"
@@ -96,7 +96,7 @@ object SourceProbe {
9696
"org.apache.skywalking.apm.agent.core.plugin.loader.AgentClassLoader"
9797
).getMethod("getDefault").invoke(null) as java.lang.ClassLoader
9898
val sizeCappedClass = Class.forName(
99-
"spp.probe.services.common.serialize.SizeCappedTypeAdapterFactory", true, agentClassLoader
99+
"spp.probe.services.common.serialize.CappedTypeAdapterFactory", true, agentClassLoader
100100
)
101101
sizeCappedClass.getMethod("setInstrumentation", Instrumentation::class.java)
102102
.invoke(null, instrumentation)
@@ -138,7 +138,7 @@ object SourceProbe {
138138
"org.apache.skywalking.apm.agent.core.plugin.loader.AgentClassLoader"
139139
).getMethod("getDefault").invoke(null) as java.lang.ClassLoader
140140
val sizeCappedClass = Class.forName(
141-
"spp.probe.services.common.serialize.SizeCappedTypeAdapterFactory", true, agentClassLoader
141+
"spp.probe.services.common.serialize.CappedTypeAdapterFactory", true, agentClassLoader
142142
)
143143
sizeCappedClass.getMethod("setInstrumentation", Instrumentation::class.java)
144144
.invoke(null, instrumentation)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#Mon Oct 25 21:48:22 EDT 2021
2+
build_date=2021-10-26T01\:48\:22.534Z
3+
build_id=401c4cab-2c7a-4658-87cc-7799553d1b1a
4+
build_version=dev
5+
apache_skywalking_version=8.9.0

e2e/docker-compose.yml

+2
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@ services:
2323
- "5445:5445"
2424
- "5450:5450"
2525
- "5455:5455"
26+
- "5107:5107"
2627
environment:
2728
- SPP_LOGGING_LEVEL=trace
2829
- SPP_OAP_HOST=skywalking-oap
30+
- JAVA_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5107
2931
volumes:
3032
- ./config/spp-platform.crt:/opt/sourceplusplus/config/spp-platform.crt
3133
- ./config/spp-platform.key:/opt/sourceplusplus/config/spp-platform.key

services/build.gradle.kts

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ dependencies {
2424
compileOnly("org.apache.skywalking:apm-agent-core:$skywalkingAgentVersion")
2525
compileOnly("net.bytebuddy:byte-buddy:1.12.8")
2626

27-
implementation("com.google.code.gson:gson:$gsonVersion")
27+
//implementation("com.google.code.gson:gson:$gsonVersion")
28+
implementation(files("../.ext/gson-2.8.6-SNAPSHOT.jar"))
2829
implementation("org.springframework:spring-expression:5.3.15")
2930
implementation("com.fasterxml.jackson.core:jackson-annotations:$jacksonVersion")
3031
implementation("org.jetbrains:annotations:23.0.0")

services/src/main/kotlin/spp/probe/services/common/ContextReceiver.kt

+10-7
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@ import spp.protocol.instrument.meter.MeterType
3737
import spp.protocol.instrument.meter.MetricValueType
3838
import java.util.*
3939
import java.util.concurrent.ConcurrentHashMap
40+
import java.util.concurrent.Executors
4041

4142
object ContextReceiver {
4243

4344
private val localVariables: MutableMap<String?, MutableMap<String, Any>> = ConcurrentHashMap()
4445
private val fields: MutableMap<String?, MutableMap<String, Any>> = ConcurrentHashMap()
4546
private val staticFields: MutableMap<String?, MutableMap<String, Any>> = ConcurrentHashMap()
4647
private val logReport = ServiceManager.INSTANCE.findService(LogReportServiceClient::class.java)
48+
private val executor = Executors.newFixedThreadPool(5)
4749

4850
operator fun get(instrumentId: String): ContextMap {
4951
val contextMap = ContextMap()
@@ -84,7 +86,7 @@ object ContextReceiver {
8486
}
8587

8688
@JvmStatic
87-
fun putBreakpoint(breakpointId: String, source: String?, line: Int, throwable: Throwable) {
89+
fun putBreakpoint(breakpointId: String, source: String?, line: Int, throwable: Throwable) = executor.submit {
8890
val activeSpan = ContextManager.createLocalSpan(throwable.stackTrace[0].toString())
8991
val localVars: Map<String, Any>? = localVariables.remove(breakpointId)
9092
localVars?.forEach { (key: String, value: Any) ->
@@ -116,7 +118,7 @@ object ContextReceiver {
116118
}
117119

118120
@JvmStatic
119-
fun putLog(logId: String?, logFormat: String?, vararg logArguments: String) {
121+
fun putLog(logId: String?, logFormat: String?, vararg logArguments: String) = executor.submit {
120122
val localVars: Map<String, Any>? = localVariables.remove(logId)
121123
val localFields: Map<String, Any>? = fields.remove(logId)
122124
val localStaticFields: Map<String, Any>? = staticFields.remove(logId)
@@ -170,8 +172,8 @@ object ContextReceiver {
170172
}
171173

172174
@JvmStatic
173-
fun putMeter(meterId: String) {
174-
val liveMeter = ProbeMemory["spp.live-meter:$meterId"] as LiveMeter? ?: return
175+
fun putMeter(meterId: String) = executor.submit {
176+
val liveMeter = ProbeMemory["spp.live-meter:$meterId"] as LiveMeter? ?: return@submit
175177
val baseMeter = ProbeMemory.computeIfAbsent("spp.base-meter:$meterId") {
176178
when (liveMeter.meterType) {
177179
MeterType.COUNT -> return@computeIfAbsent MeterFactory.counter(
@@ -224,7 +226,7 @@ object ContextReceiver {
224226
private fun encodeObject(varName: String, value: Any): String? {
225227
return try {
226228
String.format(
227-
"{\"@class\":\"%s\",\"@identity\":\"%s\",\"$varName\":%s}",
229+
"{\"@class\":\"%s\",\"@id\":\"%s\",\"$varName\":%s}",
228230
value.javaClass.name, Integer.toHexString(System.identityHashCode(value)),
229231
ModelSerializer.INSTANCE.toExtendedJson(value)
230232
)
@@ -233,8 +235,9 @@ object ContextReceiver {
233235
val map: MutableMap<String, Any?> = HashMap()
234236
map[varName] = value.javaClass.name + "@" + Integer.toHexString(System.identityHashCode(value))
235237
map["@class"] = "java.lang.Class"
236-
map["@identity"] = Integer.toHexString(System.identityHashCode(value))
237-
map["@ex"] = ex.message
238+
map["@id"] = Integer.toHexString(System.identityHashCode(value))
239+
map["@skip"] = "EXCEPTION_OCCURRED"
240+
map["@cause"] = ex.message
238241
return ModelSerializer.INSTANCE.toJson(map)
239242
} catch (ignore: Exception) {
240243
}

services/src/main/kotlin/spp/probe/services/common/ModelSerializer.kt

+5-8
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,15 @@
1717
*/
1818
package spp.probe.services.common
1919

20-
import com.google.gson.Gson
21-
import com.google.gson.GsonBuilder
22-
import com.google.gson.TypeAdapter
23-
import com.google.gson.TypeAdapterFactory
20+
import com.google.gson.*
2421
import com.google.gson.reflect.TypeToken
2522
import com.google.gson.stream.JsonReader
2623
import com.google.gson.stream.JsonWriter
27-
import spp.probe.services.common.serialize.RuntimeClassIdentityTypeAdapterFactory
2824
import spp.probe.services.common.serialize.RuntimeClassNameTypeAdapterFactory
29-
import spp.probe.services.common.serialize.SizeCappedTypeAdapterFactory
25+
import spp.probe.services.common.serialize.CappedTypeAdapterFactory
3026
import java.io.IOException
3127
import java.io.OutputStream
28+
import java.util.*
3229

3330
enum class ModelSerializer {
3431
INSTANCE;
@@ -43,7 +40,8 @@ enum class ModelSerializer {
4340

4441
private val gson: Gson = GsonBuilder().disableHtmlEscaping().create()
4542
val extendedGson: Gson = GsonBuilder()
46-
.registerTypeAdapterFactory(SizeCappedTypeAdapterFactory())
43+
.setJsogPolicy(JsogPolicy.DEFAULT.withJsogAlwaysEnabled())
44+
.registerTypeAdapterFactory(CappedTypeAdapterFactory(2))
4745
.registerTypeAdapterFactory(object : TypeAdapterFactory {
4846
override fun <T> create(gson: Gson, typeToken: TypeToken<T>): TypeAdapter<T>? {
4947
return if (ignoredTypes.contains(typeToken.rawType.name)) {
@@ -73,7 +71,6 @@ enum class ModelSerializer {
7371
} else null
7472
}
7573
})
76-
.registerTypeAdapterFactory(RuntimeClassIdentityTypeAdapterFactory.of(Any::class.java))
7774
.registerTypeAdapterFactory(RuntimeClassNameTypeAdapterFactory.of(Any::class.java))
7875
.disableHtmlEscaping().create()
7976

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Source++, the open-source live coding platform.
3+
* Copyright (C) 2022 CodeBrig, Inc.
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Affero General Public License as published
7+
* by the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Affero General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Affero General Public License
16+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
package spp.probe.services.common.serialize
19+
20+
import com.google.gson.Gson
21+
import com.google.gson.TypeAdapter
22+
import com.google.gson.TypeAdapterFactory
23+
import com.google.gson.internal.bind.JsogRegistry
24+
import com.google.gson.reflect.TypeToken
25+
import com.google.gson.stream.JsonReader
26+
import com.google.gson.stream.JsonWriter
27+
import spp.probe.services.common.ModelSerializer
28+
import java.io.IOException
29+
import java.lang.instrument.Instrumentation
30+
31+
class CappedTypeAdapterFactory(val maxDepth: Int) : TypeAdapterFactory {
32+
33+
override fun <T> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
34+
return if (instrumentation == null || maxMemorySize == -1L) null else object : TypeAdapter<T>() {
35+
36+
@Throws(IOException::class)
37+
override fun write(jsonWriter: JsonWriter, value: T?) {
38+
if (value == null) {
39+
jsonWriter.nullValue()
40+
return
41+
} else if (value is Class<*>) {
42+
jsonWriter.value(value.name)
43+
return
44+
}
45+
46+
JsogRegistry.get().userData.putIfAbsent("depth", 0)
47+
if ((JsogRegistry.get().userData["depth"] as Int) >= maxDepth) {
48+
jsonWriter.beginObject()
49+
jsonWriter.name("@skip")
50+
jsonWriter.value("MAX_DEPTH_EXCEEDED")
51+
jsonWriter.name("@class")
52+
jsonWriter.value(value.javaClass.name)
53+
jsonWriter.name("@id")
54+
jsonWriter.value(Integer.toHexString(System.identityHashCode(value)))
55+
jsonWriter.endObject()
56+
return
57+
}
58+
59+
val objSize = instrumentation!!.getObjectSize(value)
60+
if (objSize <= maxMemorySize) {
61+
JsogRegistry.get().userData["depth"] = (JsogRegistry.get().userData["depth"] as Int) + 1
62+
try {
63+
ModelSerializer.INSTANCE.extendedGson.getDelegateAdapter(
64+
this@CappedTypeAdapterFactory, type
65+
).write(jsonWriter, value)
66+
} catch (e: Exception) {
67+
jsonWriter.beginObject()
68+
jsonWriter.name("@skip")
69+
jsonWriter.value("EXCEPTION_OCCURRED")
70+
jsonWriter.name("@class")
71+
jsonWriter.value(value.javaClass.name)
72+
jsonWriter.name("@size")
73+
jsonWriter.value(objSize.toString())
74+
jsonWriter.name("@cause")
75+
jsonWriter.value(e.message)
76+
jsonWriter.name("@id")
77+
jsonWriter.value(Integer.toHexString(System.identityHashCode(value)))
78+
jsonWriter.endObject()
79+
}
80+
JsogRegistry.get().userData["depth"] = (JsogRegistry.get().userData["depth"] as Int) - 1
81+
} else {
82+
jsonWriter.beginObject()
83+
jsonWriter.name("@skip")
84+
jsonWriter.value("MAX_SIZE_EXCEEDED")
85+
jsonWriter.name("@class")
86+
jsonWriter.value(value.javaClass.name)
87+
jsonWriter.name("@size")
88+
jsonWriter.value(objSize.toString())
89+
jsonWriter.name("@id")
90+
jsonWriter.value(Integer.toHexString(System.identityHashCode(value)))
91+
jsonWriter.endObject()
92+
}
93+
}
94+
95+
override fun read(jsonReader: JsonReader): T? = null
96+
}
97+
}
98+
99+
companion object {
100+
private var instrumentation: Instrumentation? = null
101+
private var maxMemorySize: Long = -1
102+
103+
@JvmStatic
104+
fun setInstrumentation(instrumentation: Instrumentation) {
105+
Companion.instrumentation = instrumentation
106+
}
107+
108+
@JvmStatic
109+
fun setMaxMemorySize(maxMemorySize: Long) {
110+
Companion.maxMemorySize = maxMemorySize
111+
}
112+
}
113+
}

0 commit comments

Comments
 (0)