* Improve command scrubber in MongoClientTracer (#1587) * Don't scrub the command field value at all if it's a string * Use JsonWriter to improve efficiency of the scrubber * If available, user JsonWriter.Builder.maxLength to limit size of the query string
This commit is contained in:
parent
dca64662f6
commit
65a6293714
|
@ -167,7 +167,7 @@ class MongoClientTest extends MongoBaseTest {
|
||||||
collection.count() == 1
|
collection.count() == 1
|
||||||
assertTraces(2) {
|
assertTraces(2) {
|
||||||
trace(0, 1) {
|
trace(0, 1) {
|
||||||
mongoSpan(it, 0, "update", collectionName, dbName, "{\"update\":\"?\",\"ordered\":\"?\",\"updates\":[{\"q\":{\"password\":\"?\"},\"u\":{\"\$set\":{\"password\":\"?\"}}}]}")
|
mongoSpan(it, 0, "update", collectionName, dbName, "{\"update\":\"$collectionName\",\"ordered\":\"?\",\"updates\":[{\"q\":{\"password\":\"?\"},\"u\":{\"\$set\":{\"password\":\"?\"}}}]}")
|
||||||
}
|
}
|
||||||
trace(1, 1) {
|
trace(1, 1) {
|
||||||
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
|
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
|
||||||
|
@ -199,7 +199,7 @@ class MongoClientTest extends MongoBaseTest {
|
||||||
collection.count() == 0
|
collection.count() == 0
|
||||||
assertTraces(2) {
|
assertTraces(2) {
|
||||||
trace(0, 1) {
|
trace(0, 1) {
|
||||||
mongoSpan(it, 0, "delete", collectionName, dbName, "{\"delete\":\"?\",\"ordered\":\"?\",\"deletes\":[{\"q\":{\"password\":\"?\"},\"limit\":\"?\"}]}")
|
mongoSpan(it, 0, "delete", collectionName, dbName, "{\"delete\":\"$collectionName\",\"ordered\":\"?\",\"deletes\":[{\"q\":{\"password\":\"?\"},\"limit\":\"?\"}]}")
|
||||||
}
|
}
|
||||||
trace(1, 1) {
|
trace(1, 1) {
|
||||||
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
|
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import io.opentelemetry.javaagent.instrumentation.mongo.MongoClientTracer
|
||||||
|
import org.bson.BsonArray
|
||||||
|
import org.bson.BsonDocument
|
||||||
|
import org.bson.BsonInt32
|
||||||
|
import org.bson.BsonString
|
||||||
|
import spock.lang.Specification
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList
|
||||||
|
|
||||||
|
class MongoClientTracerTest extends Specification {
|
||||||
|
def 'should normalize queries to json'() {
|
||||||
|
setup:
|
||||||
|
def tracer = new MongoClientTracer()
|
||||||
|
|
||||||
|
expect:
|
||||||
|
tracer.normalizeQuery(
|
||||||
|
new BsonDocument("cmd", new BsonInt32(1))) ==
|
||||||
|
'{ "cmd" : "?" }'
|
||||||
|
|
||||||
|
tracer.normalizeQuery(
|
||||||
|
new BsonDocument("cmd", new BsonInt32(1))
|
||||||
|
.append("sub", new BsonDocument("a", new BsonInt32(1)))) ==
|
||||||
|
'{ "cmd" : "?", "sub" : { "a" : "?" } }'
|
||||||
|
|
||||||
|
tracer.normalizeQuery(
|
||||||
|
new BsonDocument("cmd", new BsonInt32(1))
|
||||||
|
.append("sub", new BsonArray(asList(new BsonInt32(1))))) ==
|
||||||
|
'{ "cmd" : "?", "sub" : ["?"] }'
|
||||||
|
}
|
||||||
|
|
||||||
|
def 'should only preserve string value if it is the value of the first top-level key'() {
|
||||||
|
setup:
|
||||||
|
def tracer = new MongoClientTracer()
|
||||||
|
|
||||||
|
expect:
|
||||||
|
tracer.normalizeQuery(
|
||||||
|
new BsonDocument("cmd", new BsonString("c"))
|
||||||
|
.append("f", new BsonString("c"))
|
||||||
|
.append("sub", new BsonString("c"))) ==
|
||||||
|
'{ "cmd" : "c", "f" : "?", "sub" : "?" }'
|
||||||
|
}
|
||||||
|
|
||||||
|
def 'should truncate simple command'() {
|
||||||
|
setup:
|
||||||
|
def tracer = new MongoClientTracer(20)
|
||||||
|
|
||||||
|
expect:
|
||||||
|
tracer.normalizeQuery(
|
||||||
|
new BsonDocument("cmd", new BsonString("c"))
|
||||||
|
.append("f1", new BsonString("c1"))
|
||||||
|
.append("f2", new BsonString("c2"))) ==
|
||||||
|
'{ "cmd" : "c", "f1" '
|
||||||
|
}
|
||||||
|
|
||||||
|
def 'should truncate array'() {
|
||||||
|
setup:
|
||||||
|
def tracer = new MongoClientTracer(27)
|
||||||
|
|
||||||
|
expect:
|
||||||
|
tracer.normalizeQuery(
|
||||||
|
new BsonDocument("cmd", new BsonString("c"))
|
||||||
|
.append("f1", new BsonArray(asList(new BsonString("c1"), new BsonString("c2"))))
|
||||||
|
.append("f2", new BsonString("c3"))) ==
|
||||||
|
'{ "cmd" : "c", "f1" : ["?",'
|
||||||
|
}
|
||||||
|
}
|
|
@ -177,7 +177,7 @@ class MongoClientTest extends MongoBaseTest {
|
||||||
collection.count() == 1
|
collection.count() == 1
|
||||||
assertTraces(2) {
|
assertTraces(2) {
|
||||||
trace(0, 1) {
|
trace(0, 1) {
|
||||||
mongoSpan(it, 0, "update", collectionName, dbName, "{\"update\":\"?\",\"ordered\":\"?\",\"updates\":[{\"q\":{\"password\":\"?\"},\"u\":{\"\$set\":{\"password\":\"?\"}}}]}")
|
mongoSpan(it, 0, "update", collectionName, dbName, "{\"update\":\"$collectionName\",\"ordered\":\"?\",\"updates\":[{\"q\":{\"password\":\"?\"},\"u\":{\"\$set\":{\"password\":\"?\"}}}]}")
|
||||||
}
|
}
|
||||||
trace(1, 1) {
|
trace(1, 1) {
|
||||||
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
|
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
|
||||||
|
@ -209,7 +209,7 @@ class MongoClientTest extends MongoBaseTest {
|
||||||
collection.count() == 0
|
collection.count() == 0
|
||||||
assertTraces(2) {
|
assertTraces(2) {
|
||||||
trace(0, 1) {
|
trace(0, 1) {
|
||||||
mongoSpan(it, 0, "delete", collectionName, dbName, "{\"delete\":\"?\",\"ordered\":\"?\",\"deletes\":[{\"q\":{\"password\":\"?\"},\"limit\":\"?\"}]}")
|
mongoSpan(it, 0, "delete", collectionName, dbName, "{\"delete\":\"$collectionName\",\"ordered\":\"?\",\"deletes\":[{\"q\":{\"password\":\"?\"},\"limit\":\"?\"}]}")
|
||||||
}
|
}
|
||||||
trace(1, 1) {
|
trace(1, 1) {
|
||||||
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
|
mongoSpan(it, 0, "count", collectionName, dbName, "{\"count\":\"$collectionName\",\"query\":{}}")
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import io.opentelemetry.javaagent.instrumentation.mongo.MongoClientTracer
|
||||||
|
import org.bson.BsonArray
|
||||||
|
import org.bson.BsonDocument
|
||||||
|
import org.bson.BsonInt32
|
||||||
|
import org.bson.BsonString
|
||||||
|
import spock.lang.Specification
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList
|
||||||
|
|
||||||
|
class MongoClientTracerTest extends Specification {
|
||||||
|
def 'should normalize queries to json'() {
|
||||||
|
setup:
|
||||||
|
def tracer = new MongoClientTracer()
|
||||||
|
|
||||||
|
expect:
|
||||||
|
tracer.normalizeQuery(
|
||||||
|
new BsonDocument("cmd", new BsonInt32(1))) ==
|
||||||
|
'{ "cmd" : "?" }'
|
||||||
|
|
||||||
|
tracer.normalizeQuery(
|
||||||
|
new BsonDocument("cmd", new BsonInt32(1))
|
||||||
|
.append("sub", new BsonDocument("a", new BsonInt32(1)))) ==
|
||||||
|
'{ "cmd" : "?", "sub" : { "a" : "?" } }'
|
||||||
|
|
||||||
|
tracer.normalizeQuery(
|
||||||
|
new BsonDocument("cmd", new BsonInt32(1))
|
||||||
|
.append("sub", new BsonArray(asList(new BsonInt32(1))))) ==
|
||||||
|
'{ "cmd" : "?", "sub" : ["?"] }'
|
||||||
|
}
|
||||||
|
|
||||||
|
def 'should only preserve string value if it is the value of the first top-level key'() {
|
||||||
|
setup:
|
||||||
|
def tracer = new MongoClientTracer()
|
||||||
|
|
||||||
|
expect:
|
||||||
|
tracer.normalizeQuery(
|
||||||
|
new BsonDocument("cmd", new BsonString("c"))
|
||||||
|
.append("f", new BsonString("c"))
|
||||||
|
.append("sub", new BsonString("c"))) ==
|
||||||
|
'{ "cmd" : "c", "f" : "?", "sub" : "?" }'
|
||||||
|
}
|
||||||
|
|
||||||
|
def 'should truncate simple command'() {
|
||||||
|
setup:
|
||||||
|
def tracer = new MongoClientTracer(20)
|
||||||
|
|
||||||
|
expect:
|
||||||
|
tracer.normalizeQuery(
|
||||||
|
new BsonDocument("cmd", new BsonString("c"))
|
||||||
|
.append("f1", new BsonString("c1"))
|
||||||
|
.append("f2", new BsonString("c2"))) ==
|
||||||
|
'{ "cmd" : "c", "f1" '
|
||||||
|
}
|
||||||
|
|
||||||
|
def 'should truncate array'() {
|
||||||
|
setup:
|
||||||
|
def tracer = new MongoClientTracer(27)
|
||||||
|
|
||||||
|
expect:
|
||||||
|
tracer.normalizeQuery(
|
||||||
|
new BsonDocument("cmd", new BsonString("c"))
|
||||||
|
.append("f1", new BsonArray(asList(new BsonString("c1"), new BsonString("c2"))))
|
||||||
|
.append("f2", new BsonString("c3"))) ==
|
||||||
|
'{ "cmd" : "c", "f1" : ["?",'
|
||||||
|
}
|
||||||
|
}
|
|
@ -222,7 +222,7 @@ class MongoAsyncClientTest extends MongoBaseTest {
|
||||||
assertTraces(2) {
|
assertTraces(2) {
|
||||||
trace(0, 1) {
|
trace(0, 1) {
|
||||||
mongoSpan(it, 0, "update", collectionName, dbName) {
|
mongoSpan(it, 0, "update", collectionName, dbName) {
|
||||||
assert it.replaceAll(" ", "") == "{\"update\":\"?\",\"ordered\":\"?\",\"updates\":[{\"q\":{\"password\":\"?\"},\"u\":{\"\$set\":{\"password\":\"?\"}}}]}" ||
|
assert it.replaceAll(" ", "") == "{\"update\":\"$collectionName\",\"ordered\":\"?\",\"updates\":[{\"q\":{\"password\":\"?\"},\"u\":{\"\$set\":{\"password\":\"?\"}}}]}" ||
|
||||||
it == "{\"update\": \"?\", \"ordered\": \"?\", \"\$db\": \"?\", \"updates\": [{\"q\": {\"password\": \"?\"}, \"u\": {\"\$set\": {\"password\": \"?\"}}}]}"
|
it == "{\"update\": \"?\", \"ordered\": \"?\", \"\$db\": \"?\", \"updates\": [{\"q\": {\"password\": \"?\"}, \"u\": {\"\$set\": {\"password\": \"?\"}}}]}"
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -271,7 +271,7 @@ class MongoAsyncClientTest extends MongoBaseTest {
|
||||||
assertTraces(2) {
|
assertTraces(2) {
|
||||||
trace(0, 1) {
|
trace(0, 1) {
|
||||||
mongoSpan(it, 0, "delete", collectionName, dbName) {
|
mongoSpan(it, 0, "delete", collectionName, dbName) {
|
||||||
assert it.replaceAll(" ", "") == "{\"delete\":\"?\",\"ordered\":\"?\",\"deletes\":[{\"q\":{\"password\":\"?\"},\"limit\":\"?\"}]}" ||
|
assert it.replaceAll(" ", "") == "{\"delete\":\"$collectionName\",\"ordered\":\"?\",\"deletes\":[{\"q\":{\"password\":\"?\"},\"limit\":\"?\"}]}" ||
|
||||||
it == "{\"delete\": \"?\", \"ordered\": \"?\", \"\$db\": \"?\", \"deletes\": [{\"q\": {\"password\": \"?\"}, \"limit\": \"?\"}]}"
|
it == "{\"delete\": \"?\", \"ordered\": \"?\", \"\$db\": \"?\", \"deletes\": [{\"q\": {\"password\": \"?\"}, \"limit\": \"?\"}]}"
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,18 +12,34 @@ import io.opentelemetry.api.trace.Span;
|
||||||
import io.opentelemetry.api.trace.attributes.SemanticAttributes;
|
import io.opentelemetry.api.trace.attributes.SemanticAttributes;
|
||||||
import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer;
|
import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer;
|
||||||
import io.opentelemetry.javaagent.instrumentation.api.db.DbSystem;
|
import io.opentelemetry.javaagent.instrumentation.api.db.DbSystem;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import org.bson.BsonArray;
|
import org.bson.BsonArray;
|
||||||
import org.bson.BsonDocument;
|
import org.bson.BsonDocument;
|
||||||
import org.bson.BsonString;
|
|
||||||
import org.bson.BsonValue;
|
import org.bson.BsonValue;
|
||||||
|
import org.bson.json.JsonWriter;
|
||||||
|
import org.bson.json.JsonWriterSettings;
|
||||||
|
|
||||||
public class MongoClientTracer extends DatabaseClientTracer<CommandStartedEvent, BsonDocument> {
|
public class MongoClientTracer extends DatabaseClientTracer<CommandStartedEvent, BsonDocument> {
|
||||||
private static final MongoClientTracer TRACER = new MongoClientTracer();
|
private static final MongoClientTracer TRACER = new MongoClientTracer();
|
||||||
|
|
||||||
|
private final int maxNormalizedQueryLength;
|
||||||
|
private final JsonWriterSettings jsonWriterSettings;
|
||||||
|
|
||||||
|
public MongoClientTracer() {
|
||||||
|
this(32 * 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MongoClientTracer(int maxNormalizedQueryLength) {
|
||||||
|
this.maxNormalizedQueryLength = maxNormalizedQueryLength;
|
||||||
|
this.jsonWriterSettings = createJsonWriterSettings(maxNormalizedQueryLength);
|
||||||
|
}
|
||||||
|
|
||||||
public static MongoClientTracer tracer() {
|
public static MongoClientTracer tracer() {
|
||||||
return TRACER;
|
return TRACER;
|
||||||
}
|
}
|
||||||
|
@ -80,54 +96,120 @@ public class MongoClientTracer extends DatabaseClientTracer<CommandStartedEvent,
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Method IS_TRUNCATED_METHOD;
|
||||||
|
|
||||||
|
static {
|
||||||
|
IS_TRUNCATED_METHOD =
|
||||||
|
Arrays.stream(JsonWriter.class.getMethods())
|
||||||
|
.filter(method -> method.getName().equals("isTruncated"))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonWriterSettings createJsonWriterSettings(int maxNormalizedQueryLength) {
|
||||||
|
JsonWriterSettings settings = new JsonWriterSettings(false);
|
||||||
|
try {
|
||||||
|
// The static JsonWriterSettings.builder() method was introduced in the 3.5 release
|
||||||
|
Optional<Method> buildMethod =
|
||||||
|
Arrays.stream(JsonWriterSettings.class.getMethods())
|
||||||
|
.filter(method -> method.getName().equals("builder"))
|
||||||
|
.findFirst();
|
||||||
|
if (buildMethod.isPresent()) {
|
||||||
|
Class<?> builderClass = buildMethod.get().getReturnType();
|
||||||
|
Object builder = buildMethod.get().invoke(null, (Object[]) null);
|
||||||
|
|
||||||
|
// The JsonWriterSettings.Builder.indent method was introduced in the 3.5 release,
|
||||||
|
// but checking anyway
|
||||||
|
Optional<Method> indentMethod =
|
||||||
|
Arrays.stream(builderClass.getMethods())
|
||||||
|
.filter(method -> method.getName().equals("indent"))
|
||||||
|
.findFirst();
|
||||||
|
if (indentMethod.isPresent()) {
|
||||||
|
indentMethod.get().invoke(builder, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The JsonWriterSettings.Builder.maxLength method was introduced in the 3.7 release
|
||||||
|
Optional<Method> maxLengthMethod =
|
||||||
|
Arrays.stream(builderClass.getMethods())
|
||||||
|
.filter(method -> method.getName().equals("maxLength"))
|
||||||
|
.findFirst();
|
||||||
|
if (maxLengthMethod.isPresent()) {
|
||||||
|
maxLengthMethod.get().invoke(builder, maxNormalizedQueryLength);
|
||||||
|
}
|
||||||
|
settings =
|
||||||
|
(JsonWriterSettings)
|
||||||
|
builderClass.getMethod("build", (Class<?>[]) null).invoke(builder, (Object[]) null);
|
||||||
|
}
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException ignored) {
|
||||||
|
}
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String normalizeQuery(BsonDocument statement) {
|
public String normalizeQuery(BsonDocument command) {
|
||||||
// scrub the Mongo command so that parameters are removed from the string
|
StringWriter stringWriter = new StringWriter(128);
|
||||||
BsonDocument scrubbed = scrub(statement);
|
writeScrubbed(command, new JsonWriter(stringWriter, jsonWriterSettings), true);
|
||||||
return scrubbed.toString();
|
// If using MongoDB driver >= 3.7, the substring invocation will be a no-op due to use of
|
||||||
|
// JsonWriterSettings.Builder.maxLength in the static initializer for JSON_WRITER_SETTINGS
|
||||||
|
return stringWriter
|
||||||
|
.getBuffer()
|
||||||
|
.substring(0, Math.min(maxNormalizedQueryLength, stringWriter.getBuffer().length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static final String HIDDEN_CHAR = "?";
|
||||||
* The values of these mongo fields will not be scrubbed out. This allows the non-sensitive
|
|
||||||
* collection names to be captured.
|
|
||||||
*/
|
|
||||||
private static final List<String> UNSCRUBBED_FIELDS =
|
|
||||||
Arrays.asList("ordered", "insert", "count", "find", "create");
|
|
||||||
|
|
||||||
private static final BsonValue HIDDEN_CHAR = new BsonString("?");
|
private static boolean writeScrubbed(BsonDocument origin, JsonWriter writer, boolean isRoot) {
|
||||||
|
writer.writeStartDocument();
|
||||||
private static BsonDocument scrub(BsonDocument origin) {
|
boolean firstField = true;
|
||||||
BsonDocument scrub = new BsonDocument();
|
|
||||||
for (Map.Entry<String, BsonValue> entry : origin.entrySet()) {
|
for (Map.Entry<String, BsonValue> entry : origin.entrySet()) {
|
||||||
if (UNSCRUBBED_FIELDS.contains(entry.getKey()) && entry.getValue().isString()) {
|
writer.writeName(entry.getKey());
|
||||||
scrub.put(entry.getKey(), entry.getValue());
|
// the first field of the root document is the command name, so we preserve its value
|
||||||
|
// (which for most CRUD commands is the collection name)
|
||||||
|
if (isRoot && firstField && entry.getValue().isString()) {
|
||||||
|
writer.writeString(entry.getValue().asString().getValue());
|
||||||
} else {
|
} else {
|
||||||
BsonValue child = scrub(entry.getValue());
|
if (writeScrubbed(entry.getValue(), writer)) {
|
||||||
scrub.put(entry.getKey(), child);
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return scrub;
|
firstField = false;
|
||||||
|
}
|
||||||
|
writer.writeEndDocument();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BsonValue scrub(BsonArray origin) {
|
private static boolean writeScrubbed(BsonArray origin, JsonWriter writer) {
|
||||||
BsonArray scrub = new BsonArray();
|
writer.writeStartArray();
|
||||||
for (BsonValue value : origin) {
|
for (BsonValue value : origin) {
|
||||||
BsonValue child = scrub(value);
|
if (writeScrubbed(value, writer)) {
|
||||||
scrub.add(child);
|
return true;
|
||||||
}
|
}
|
||||||
return scrub;
|
}
|
||||||
|
writer.writeEndArray();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BsonValue scrub(BsonValue origin) {
|
private static boolean writeScrubbed(BsonValue origin, JsonWriter writer) {
|
||||||
BsonValue scrubbed;
|
|
||||||
if (origin.isDocument()) {
|
if (origin.isDocument()) {
|
||||||
scrubbed = scrub(origin.asDocument());
|
return writeScrubbed(origin.asDocument(), writer, false);
|
||||||
} else if (origin.isArray()) {
|
} else if (origin.isArray()) {
|
||||||
scrubbed = scrub(origin.asArray());
|
return writeScrubbed(origin.asArray(), writer);
|
||||||
} else {
|
} else {
|
||||||
scrubbed = HIDDEN_CHAR;
|
writer.writeString(HIDDEN_CHAR);
|
||||||
|
return isTruncated(writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isTruncated(JsonWriter writer) {
|
||||||
|
if (IS_TRUNCATED_METHOD == null) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
return (boolean) IS_TRUNCATED_METHOD.invoke(writer, (Object[]) null);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException ignored) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return scrubbed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String collectionName(CommandStartedEvent event) {
|
private static String collectionName(CommandStartedEvent event) {
|
||||||
|
|
Loading…
Reference in New Issue