未验证 提交 9442a51c 编写于 作者: L Lu Jiajing 提交者: GitHub

JsonLogger implementation (#5356) (#5357)

上级 cbb2e179
......@@ -27,4 +27,12 @@
<artifactId>apm-datacarrier</artifactId>
<dependencies>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
......@@ -33,4 +33,12 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
......@@ -149,7 +149,7 @@ public class ConfigInitializer {
String propertyStringKey = propertyKey.toString();
if (propertyStringKey.startsWith(prefix) && propertyStringKey.endsWith(suffix)) {
String itemKey = propertyStringKey.substring(
prefix.length(), propertyStringKey.length() - suffix.length());
prefix.length(), propertyStringKey.length() - suffix.length());
Object keyObj;
Object valueObj;
......
......@@ -104,6 +104,11 @@
<version>${ststem-rules.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
......
......@@ -20,9 +20,11 @@ package org.apache.skywalking.apm.agent.core.conf;
import java.util.HashMap;
import java.util.Map;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.logging.core.LogLevel;
import org.apache.skywalking.apm.agent.core.logging.core.LogOutput;
import org.apache.skywalking.apm.agent.core.logging.core.ResolverType;
import org.apache.skywalking.apm.agent.core.logging.core.WriterFactory;
import org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ClassCacheMode;
import org.apache.skywalking.apm.util.Length;
......@@ -249,6 +251,11 @@ public class Config {
*/
public static LogOutput OUTPUT = LogOutput.FILE;
/**
* The log resolver type. Default is PATTERN which will create PatternLogResolver later.
*/
public static ResolverType RESOLVER = ResolverType.PATTERN;
/**
* The log patten. Default is "%level %timestamp %thread %class : %msg %throwable". Each conversion specifiers
* starts with a percent sign '%' and fis followed by conversion word. There are some default conversion
......
......@@ -32,6 +32,8 @@ import org.apache.skywalking.apm.agent.core.boot.AgentPackageNotFoundException;
import org.apache.skywalking.apm.agent.core.boot.AgentPackagePath;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
import org.apache.skywalking.apm.agent.core.logging.core.JsonLogResolver;
import org.apache.skywalking.apm.agent.core.logging.core.PatternLogResolver;
import org.apache.skywalking.apm.util.ConfigInitializer;
import org.apache.skywalking.apm.util.PropertyPlaceholderHelper;
import org.apache.skywalking.apm.util.StringUtil;
......@@ -40,7 +42,7 @@ import org.apache.skywalking.apm.util.StringUtil;
* The <code>SnifferConfigInitializer</code> initializes all configs in several way.
*/
public class SnifferConfigInitializer {
private static final ILog LOGGER = LogManager.getLogger(SnifferConfigInitializer.class);
private static ILog LOGGER = LogManager.getLogger(SnifferConfigInitializer.class);
private static final String SPECIFIED_CONFIG_PATH = "skywalking_config";
private static final String DEFAULT_CONFIG_FILE_NAME = "/config/agent.config";
private static final String ENV_KEY_PREFIX = "skywalking.";
......@@ -90,6 +92,9 @@ public class SnifferConfigInitializer {
}
initializeConfig(Config.class);
// reconfigure logger after config initialization
configureLogger();
LOGGER = LogManager.getLogger(SnifferConfigInitializer.class);
if (StringUtil.isEmpty(Config.Agent.SERVICE_NAME)) {
throw new ExceptionInInitializerError("`agent.service_name` is missing.");
......@@ -207,4 +212,15 @@ public class SnifferConfigInitializer {
}
throw new ConfigNotFoundException("Failed to load agent.config.");
}
static void configureLogger() {
switch (Config.Logging.RESOLVER) {
case JSON:
LogManager.setLogResolver(new JsonLogResolver());
break;
case PATTERN:
default:
LogManager.setLogResolver(new PatternLogResolver());
}
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.agent.core.logging.core;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.core.converters.AgentNameConverter;
import org.apache.skywalking.apm.agent.core.logging.core.converters.ClassConverter;
import org.apache.skywalking.apm.agent.core.logging.core.converters.DateConverter;
import org.apache.skywalking.apm.agent.core.logging.core.converters.LevelConverter;
import org.apache.skywalking.apm.agent.core.logging.core.converters.MessageConverter;
import org.apache.skywalking.apm.agent.core.logging.core.converters.ThreadConverter;
import org.apache.skywalking.apm.agent.core.logging.core.converters.ThrowableConverter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
/**
* An abstract class to simplify the real implementation of the loggers.
* It hold the class name of the logger, and is responsible for log level check,
* message interpolation, etc.
*/
public abstract class AbstractLogger implements ILog {
public static final Map<String, Class<? extends Converter>> DEFAULT_CONVERTER_MAP = new HashMap<>();
protected List<Converter> converters = new ArrayList<>();
static {
DEFAULT_CONVERTER_MAP.put("thread", ThreadConverter.class);
DEFAULT_CONVERTER_MAP.put("level", LevelConverter.class);
DEFAULT_CONVERTER_MAP.put("agent_name", AgentNameConverter.class);
DEFAULT_CONVERTER_MAP.put("timestamp", DateConverter.class);
DEFAULT_CONVERTER_MAP.put("msg", MessageConverter.class);
DEFAULT_CONVERTER_MAP.put("throwable", ThrowableConverter.class);
DEFAULT_CONVERTER_MAP.put("class", ClassConverter.class);
}
protected final String targetClass;
public AbstractLogger(String targetClass) {
this.targetClass = targetClass;
}
@Override
public void info(String message) {
if (this.isInfoEnable()) {
this.logger(LogLevel.INFO, message, null);
}
}
@Override
public void info(String message, Object... objects) {
if (this.isInfoEnable()) {
this.logger(LogLevel.INFO, replaceParam(message, objects), null);
}
}
@Override
public void warn(String message, Object... objects) {
if (this.isWarnEnable()) {
this.logger(LogLevel.WARN, replaceParam(message, objects), null);
}
}
@Override
public void warn(Throwable throwable, String message, Object... objects) {
if (this.isWarnEnable()) {
this.logger(LogLevel.WARN, replaceParam(message, objects), throwable);
}
}
@Override
public void error(String message, Throwable throwable) {
if (this.isErrorEnable()) {
this.logger(LogLevel.ERROR, message, throwable);
}
}
@Override
public void error(Throwable throwable, String message, Object... objects) {
if (this.isErrorEnable()) {
this.logger(LogLevel.ERROR, replaceParam(message, objects), throwable);
}
}
@Override
public void error(String message) {
if (this.isErrorEnable()) {
this.logger(LogLevel.ERROR, message, null);
}
}
@Override
public void debug(String message) {
if (this.isDebugEnable()) {
this.logger(LogLevel.DEBUG, message, null);
}
}
@Override
public void debug(String message, Object... objects) {
if (this.isDebugEnable()) {
this.logger(LogLevel.DEBUG, replaceParam(message, objects), null);
}
}
@Override
public void debug(Throwable throwable, String message, Object... objects) {
if (this.isDebugEnable()) {
this.logger(LogLevel.DEBUG, replaceParam(message, objects), throwable);
}
}
public boolean isDebugEnable() {
return LogLevel.DEBUG.compareTo(Config.Logging.LEVEL) >= 0;
}
public boolean isInfoEnable() {
return LogLevel.INFO.compareTo(Config.Logging.LEVEL) >= 0;
}
public boolean isWarnEnable() {
return LogLevel.WARN.compareTo(Config.Logging.LEVEL) >= 0;
}
public boolean isErrorEnable() {
return LogLevel.ERROR.compareTo(Config.Logging.LEVEL) >= 0;
}
protected String replaceParam(String message, Object... parameters) {
if (message == null) {
return message;
}
int startSize = 0;
int parametersIndex = 0;
int index;
String tmpMessage = message;
while ((index = message.indexOf("{}", startSize)) != -1) {
if (parametersIndex >= parameters.length) {
break;
}
/**
* @Fix the Illegal group reference issue
*/
tmpMessage = tmpMessage.replaceFirst("\\{\\}", Matcher.quoteReplacement(String.valueOf(parameters[parametersIndex++])));
startSize = index + 2;
}
return tmpMessage;
}
protected void logger(LogLevel level, String message, Throwable e) {
WriterFactory.getLogWriter().write(this.format(level, message, e));
}
/**
* The abstract method left for real loggers.
* Any implementation MUST return string, which will be directly transferred to log destination,
* i.e. log files OR stdout
*
* @param level log level
* @param message log message, which has been interpolated with user-defined parameters.
* @param e throwable if exists
* @return string representation of the log, for example, raw json string for {@link JsonLogger}
*/
protected abstract String format(LogLevel level, String message, Throwable e);
}
......@@ -19,10 +19,12 @@
package org.apache.skywalking.apm.agent.core.logging.core;
/**
* The Converter, It is used to convert the LogEvent to the String.
* The Converter, it is used to convert the LogEvent to the String.
* For JsonLogger, the `getKey()` method is used to generate the key for json.
*/
public interface Converter {
String convert(LogEvent logEvent);
String getKey();
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.agent.core.logging.core;
import com.google.gson.Gson;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.api.LogResolver;
public class JsonLogResolver implements LogResolver {
private static final Gson GSON = new Gson();
@Override
public ILog getLogger(Class<?> aClass) {
return new JsonLogger(aClass, GSON);
}
@Override
public ILog getLogger(String s) {
return new JsonLogger(s, GSON);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.agent.core.logging.core;
import com.google.gson.Gson;
import org.apache.skywalking.apm.agent.core.logging.core.converters.LiteralConverter;
import java.util.HashMap;
import java.util.Map;
/**
* An alternative logger for the SkyWalking agent. The default layout is
* {
* "@timestamp": "", // timestamp
* "logger": "", // name of the Logger
* "level": "", // info|debug|warn|error
* "thread": "", // thread where the log method is called
* "message": "", // your log message
* "throwable": "",
* "agent_name" "service_name"
* }
*/
public class JsonLogger extends AbstractLogger {
private final Gson gson;
public JsonLogger(Class<?> targetClass, Gson gson) {
this(targetClass.getSimpleName(), gson);
}
/**
* In the Constructor, the instances of converters are created,
* except those {@link LiteralConverter} since this class is used
* only the literals in {@link PatternLogger} ,
* and thus should not be added to the json log.
*
* @param targetClass the logger class
* @param gson instance of Gson works as json serializer
*/
public JsonLogger(String targetClass, Gson gson) {
super(targetClass);
this.gson = gson;
for (Map.Entry<String, Class<? extends Converter>> entry : DEFAULT_CONVERTER_MAP.entrySet()) {
final Class<? extends Converter> converterClass = entry.getValue();
try {
if (converters instanceof LiteralConverter) {
continue;
}
converters.add(converterClass.newInstance());
} catch (IllegalAccessException | InstantiationException e) {
throw new IllegalStateException("Create Converter error. Class: " + converterClass, e);
}
}
}
@Override
protected String format(LogLevel level, String message, Throwable e) {
LogEvent logEvent = new LogEvent(level, message, e, this.targetClass);
Map<String, String> log = new HashMap<>();
for (Converter converter : this.converters) {
log.put(converter.getKey(), converter.convert(logEvent));
}
return this.gson.toJson(log);
}
}
......@@ -18,7 +18,7 @@
package org.apache.skywalking.apm.agent.core.logging.core;
import org.apache.skywalking.apm.agent.core.logging.core.coverts.LiteralConverter;
import org.apache.skywalking.apm.agent.core.logging.core.converters.LiteralConverter;
import java.util.ArrayList;
import java.util.List;
......
......@@ -18,53 +18,25 @@
package org.apache.skywalking.apm.agent.core.logging.core;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.core.coverts.AgentNameConverter;
import org.apache.skywalking.apm.agent.core.logging.core.coverts.ClassConverter;
import org.apache.skywalking.apm.agent.core.logging.core.coverts.DateConverter;
import org.apache.skywalking.apm.agent.core.logging.core.coverts.LevelConverter;
import org.apache.skywalking.apm.agent.core.logging.core.coverts.MessageConverter;
import org.apache.skywalking.apm.agent.core.logging.core.coverts.ThreadConverter;
import org.apache.skywalking.apm.agent.core.logging.core.coverts.ThrowableConverter;
import org.apache.skywalking.apm.util.StringUtil;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
/**
* A flexible Logger configurable with pattern string. This is default implementation of {@link ILog} This can parse a
* pattern to the List of converter with Parser. We package LogEvent with message, level,timestamp ..., passing around
* to the List of converter to concat actually Log-String.
*/
public class PatternLogger implements ILog {
public static final Map<String, Class<? extends Converter>> DEFAULT_CONVERTER_MAP = new HashMap<String, Class<? extends Converter>>();
static {
DEFAULT_CONVERTER_MAP.put("thread", ThreadConverter.class);
DEFAULT_CONVERTER_MAP.put("level", LevelConverter.class);
DEFAULT_CONVERTER_MAP.put("agent_name", AgentNameConverter.class);
DEFAULT_CONVERTER_MAP.put("timestamp", DateConverter.class);
DEFAULT_CONVERTER_MAP.put("msg", MessageConverter.class);
DEFAULT_CONVERTER_MAP.put("throwable", ThrowableConverter.class);
DEFAULT_CONVERTER_MAP.put("class", ClassConverter.class);
}
public class PatternLogger extends AbstractLogger {
public static final String DEFAULT_PATTERN = "%level %timestamp %thread %class : %msg %throwable";
private String pattern;
private List<Converter> converters;
private String targetClass;
public PatternLogger(Class targetClass, String pattern) {
public PatternLogger(Class<?> targetClass, String pattern) {
this(targetClass.getSimpleName(), pattern);
}
public PatternLogger(String targetClass, String pattern) {
this.targetClass = targetClass;
super(targetClass);
this.setPattern(pattern);
}
......@@ -77,122 +49,14 @@ public class PatternLogger implements ILog {
pattern = DEFAULT_PATTERN;
}
this.pattern = pattern;
converters = new Parser(pattern, DEFAULT_CONVERTER_MAP).parse();
}
protected void logger(LogLevel level, String message, Throwable e) {
WriterFactory.getLogWriter().write(format(level, message, e));
}
private String replaceParam(String message, Object... parameters) {
if (message == null) {
return message;
}
int startSize = 0;
int parametersIndex = 0;
int index;
String tmpMessage = message;
while ((index = message.indexOf("{}", startSize)) != -1) {
if (parametersIndex >= parameters.length) {
break;
}
/**
* @Fix the Illegal group reference issue
*/
tmpMessage = tmpMessage.replaceFirst("\\{\\}", Matcher.quoteReplacement(String.valueOf(parameters[parametersIndex++])));
startSize = index + 2;
}
return tmpMessage;
}
@Override
public void info(String format) {
if (isInfoEnable())
logger(LogLevel.INFO, format, null);
}
@Override
public void info(String format, Object... arguments) {
if (isInfoEnable())
logger(LogLevel.INFO, replaceParam(format, arguments), null);
}
@Override
public void warn(String format, Object... arguments) {
if (isWarnEnable())
logger(LogLevel.WARN, replaceParam(format, arguments), null);
}
@Override
public void warn(Throwable e, String format, Object... arguments) {
if (isWarnEnable())
logger(LogLevel.WARN, replaceParam(format, arguments), e);
}
@Override
public void error(String format, Throwable e) {
if (isErrorEnable())
logger(LogLevel.ERROR, format, e);
}
@Override
public void error(Throwable e, String format, Object... arguments) {
if (isErrorEnable())
logger(LogLevel.ERROR, replaceParam(format, arguments), e);
}
@Override
public boolean isDebugEnable() {
return LogLevel.DEBUG.compareTo(Config.Logging.LEVEL) >= 0;
}
@Override
public boolean isInfoEnable() {
return LogLevel.INFO.compareTo(Config.Logging.LEVEL) >= 0;
}
@Override
public boolean isWarnEnable() {
return LogLevel.WARN.compareTo(Config.Logging.LEVEL) >= 0;
}
@Override
public boolean isErrorEnable() {
return LogLevel.ERROR.compareTo(Config.Logging.LEVEL) >= 0;
}
@Override
public void debug(String format) {
if (isDebugEnable()) {
logger(LogLevel.DEBUG, format, null);
}
}
@Override
public void debug(String format, Object... arguments) {
if (isDebugEnable()) {
logger(LogLevel.DEBUG, replaceParam(format, arguments), null);
}
this.converters = new Parser(pattern, DEFAULT_CONVERTER_MAP).parse();
}
@Override
public void error(String format) {
if (isErrorEnable()) {
logger(LogLevel.ERROR, format, null);
}
}
@Override
public void debug(final Throwable t, final String format, final Object... arguments) {
if (isDebugEnable()) {
logger(LogLevel.DEBUG, replaceParam(format, arguments), t);
}
}
String format(LogLevel level, String message, Throwable t) {
protected String format(LogLevel level, String message, Throwable t) {
LogEvent logEvent = new LogEvent(level, message, t, targetClass);
StringBuilder stringBuilder = new StringBuilder();
for (Converter converter : converters) {
for (Converter converter : this.converters) {
stringBuilder.append(converter.convert(logEvent));
}
return stringBuilder.toString();
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.agent.core.logging.core;
public enum ResolverType {
JSON, PATTERN
}
......@@ -16,7 +16,7 @@
*
*/
package org.apache.skywalking.apm.agent.core.logging.core.coverts;
package org.apache.skywalking.apm.agent.core.logging.core.converters;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.logging.core.Converter;
......@@ -27,4 +27,9 @@ public class AgentNameConverter implements Converter {
public String convert(LogEvent logEvent) {
return Config.Agent.SERVICE_NAME;
}
@Override
public String getKey() {
return "agent_name";
}
}
......@@ -16,7 +16,7 @@
*
*/
package org.apache.skywalking.apm.agent.core.logging.core.coverts;
package org.apache.skywalking.apm.agent.core.logging.core.converters;
import org.apache.skywalking.apm.agent.core.logging.core.Converter;
import org.apache.skywalking.apm.agent.core.logging.core.LogEvent;
......@@ -30,4 +30,9 @@ public class ClassConverter implements Converter {
public String convert(LogEvent logEvent) {
return logEvent.getTargetClass();
}
@Override
public String getKey() {
return "logger";
}
}
......@@ -16,7 +16,7 @@
*
*/
package org.apache.skywalking.apm.agent.core.logging.core.coverts;
package org.apache.skywalking.apm.agent.core.logging.core.converters;
import org.apache.skywalking.apm.agent.core.logging.core.Converter;
import org.apache.skywalking.apm.agent.core.logging.core.LogEvent;
......@@ -33,4 +33,9 @@ public class DateConverter implements Converter {
public String convert(LogEvent logEvent) {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(new Date());
}
@Override
public String getKey() {
return "@timestamp";
}
}
......@@ -16,7 +16,7 @@
*
*/
package org.apache.skywalking.apm.agent.core.logging.core.coverts;
package org.apache.skywalking.apm.agent.core.logging.core.converters;
import org.apache.skywalking.apm.agent.core.logging.core.Converter;
import org.apache.skywalking.apm.agent.core.logging.core.LogEvent;
......@@ -29,4 +29,9 @@ public class LevelConverter implements Converter {
public String convert(LogEvent logEvent) {
return logEvent.getLevel().name();
}
@Override
public String getKey() {
return "level";
}
}
......@@ -16,7 +16,7 @@
*
*/
package org.apache.skywalking.apm.agent.core.logging.core.coverts;
package org.apache.skywalking.apm.agent.core.logging.core.converters;
import org.apache.skywalking.apm.agent.core.logging.core.Converter;
import org.apache.skywalking.apm.agent.core.logging.core.LogEvent;
......@@ -36,4 +36,9 @@ public class LiteralConverter implements Converter {
public String convert(LogEvent logEvent) {
return literal;
}
@Override
public String getKey() {
return "";
}
}
......@@ -16,7 +16,7 @@
*
*/
package org.apache.skywalking.apm.agent.core.logging.core.coverts;
package org.apache.skywalking.apm.agent.core.logging.core.converters;
import org.apache.skywalking.apm.agent.core.logging.core.Converter;
import org.apache.skywalking.apm.agent.core.logging.core.LogEvent;
......@@ -29,4 +29,9 @@ public class MessageConverter implements Converter {
public String convert(LogEvent logEvent) {
return logEvent.getMessage();
}
@Override
public String getKey() {
return "message";
}
}
......@@ -16,7 +16,7 @@
*
*/
package org.apache.skywalking.apm.agent.core.logging.core.coverts;
package org.apache.skywalking.apm.agent.core.logging.core.converters;
import org.apache.skywalking.apm.agent.core.logging.core.Converter;
import org.apache.skywalking.apm.agent.core.logging.core.LogEvent;
......@@ -29,4 +29,9 @@ public class ThreadConverter implements Converter {
public String convert(LogEvent logEvent) {
return Thread.currentThread().getName();
}
@Override
public String getKey() {
return "thread";
}
}
......@@ -16,7 +16,7 @@
*
*/
package org.apache.skywalking.apm.agent.core.logging.core.coverts;
package org.apache.skywalking.apm.agent.core.logging.core.converters;
import org.apache.skywalking.apm.agent.core.conf.Constants;
import org.apache.skywalking.apm.agent.core.logging.core.Converter;
......@@ -46,4 +46,9 @@ public class ThrowableConverter implements Converter {
}
return Constants.LINE_SEPARATOR + expMessage;
}
@Override
public String getKey() {
return "throwable";
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.agent.core.logging.core;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.logging.core.converters.ThrowableConverter;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeDiagnosingMatcher;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import java.lang.reflect.Type;
import java.util.Map;
import static org.mockito.Mockito.times;
public class JsonLoggerTest {
@BeforeClass
public static void initAndHoldOut() {
Config.Agent.SERVICE_NAME = "testAppFromConfig";
}
@Test
public void testLog() {
final IWriter output = Mockito.mock(IWriter.class);
JsonLogger logger = new JsonLogger(JsonLoggerTest.class, new Gson()) {
@Override
protected void logger(LogLevel level, String message, Throwable e) {
output.write(format(level, message, e));
}
};
Assert.assertTrue(logger.isDebugEnable());
Assert.assertTrue(logger.isInfoEnable());
Assert.assertTrue(logger.isWarnEnable());
Assert.assertTrue(logger.isErrorEnable());
ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
logger.debug("hello world");
Mockito.verify(output, times(1)).write(argument.capture());
Assert.assertThat(argument.getValue(), createMatcher("hello world", "DEBUG", null));
logger.debug("hello {}", "world");
Mockito.verify(output, times(2)).write(argument.capture());
Assert.assertThat(argument.getValue(), createMatcher("hello world", "DEBUG", null));
logger.info("hello world");
Mockito.verify(output, times(3)).write(argument.capture());
Assert.assertThat(argument.getValue(), createMatcher("hello world", "INFO", null));
logger.info("hello {}", "world");
Mockito.verify(output, times(4)).write(argument.capture());
Assert.assertThat(argument.getValue(), createMatcher("hello world", "INFO", null));
logger.warn("hello {}", "world");
Mockito.verify(output, times(5)).write(argument.capture());
Assert.assertThat(argument.getValue(), createMatcher("hello world", "WARN", null));
logger.warn("hello world");
Mockito.verify(output, times(6)).write(argument.capture());
Assert.assertThat(argument.getValue(), createMatcher("hello world", "WARN", null));
logger.error("hello world");
Mockito.verify(output, times(7)).write(argument.capture());
Assert.assertThat(argument.getValue(), createMatcher("hello world", "ERROR", null));
Throwable t = new NullPointerException();
logger.error("hello world", t);
Mockito.verify(output, times(8)).write(argument.capture());
Assert.assertThat(argument.getValue(), createMatcher("hello world", "ERROR", t));
logger.error(t, "hello {}", "world");
Mockito.verify(output, times(9)).write(argument.capture());
Assert.assertThat(argument.getValue(), createMatcher("hello world", "ERROR", t));
}
private static class LogMatcher extends TypeSafeDiagnosingMatcher<String> {
private static final Gson GSON = new Gson();
private static final Type MAP_TYPE = new TypeToken<Map<String, String>>() {
}.getType();
private final String agent;
private final String logger;
private final String message;
private final String level;
private final Throwable t;
public LogMatcher(String agent, String logger, String message, String level, Throwable t) {
this.agent = agent;
this.logger = logger;
this.message = message;
this.level = level;
this.t = t;
}
@Override
protected boolean matchesSafely(String item, Description mismatchDescription) {
try {
Map<String, String> logMap = GSON.fromJson(item, MAP_TYPE);
if (!logMap.containsKey("agent_name")) {
mismatchDescription.appendText("agent_name did not exist");
return false;
}
if (!this.agent.equals(logMap.get("agent_name"))) {
mismatchDescription.appendText("agent_name was " + this.agent);
return false;
}
if (!logMap.containsKey("message")) {
mismatchDescription.appendText("agent_name did not exist");
return false;
}
if (!this.message.equals(logMap.get("message"))) {
mismatchDescription.appendText("message was " + this.message);
return false;
}
if (!logMap.containsKey("@timestamp")) {
mismatchDescription.appendText("@timestamp did not exist");
return false;
}
if (!logMap.containsKey("level")) {
mismatchDescription.appendText("level did not exist");
return false;
}
if (!this.level.equals(logMap.get("level"))) {
mismatchDescription.appendText("level was " + this.level);
return false;
}
if (!logMap.containsKey("logger")) {
mismatchDescription.appendText("logger did not exist");
return false;
}
if (!this.logger.equals(logMap.get("logger"))) {
mismatchDescription.appendText("logger was " + this.logger);
return false;
}
if (!logMap.containsKey("throwable")) {
mismatchDescription.appendText("throwable did not exist");
return false;
}
final String tStr = this.t == null ? "" : ThrowableConverter.format(this.t);
if (!tStr.equals(logMap.get("throwable"))) {
mismatchDescription.appendText("throwable was " + tStr);
return false;
}
} catch (JsonSyntaxException ex) {
mismatchDescription.appendText("not a valid json string");
return false;
}
return true;
}
@Override
public void describeTo(Description expectation) {
expectation.appendText(
String.format("a valid json log format with {message=%s,level=%s,logger=%s,@timestamp=*,agent=%s}",
message, level, logger, agent));
}
}
public static LogMatcher createMatcher(String message, String level, Throwable t) {
return new LogMatcher("testAppFromConfig", JsonLoggerTest.class.getSimpleName(), message, level, t);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.agent.core.logging.core;
import com.google.gson.Gson;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import java.util.concurrent.TimeUnit;
public class LoggingBenchmark {
private static final PatternLogger PATTERN_LOGGER = new PatternLogger(LoggingBenchmark.class, PatternLogger.DEFAULT_PATTERN) {
@Override
protected void logger(LogLevel level, String message, Throwable e) {
format(level, message, e);
}
};
private static final JsonLogger JSON_LOGGER = new JsonLogger(LoggingBenchmark.class, new Gson()) {
@Override
protected void logger(LogLevel level, String message, Throwable e) {
format(level, message, e);
}
};
@Benchmark
@Fork(value = 1, warmups = 1)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.SampleTime)
public void jsonLogger() {
JSON_LOGGER.info("Hello World");
}
@Benchmark
@Fork(value = 1, warmups = 1)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.SampleTime)
public void patternLogger() {
PATTERN_LOGGER.info("Hello World");
}
public static void main(String[] args) throws Exception {
org.openjdk.jmh.Main.main(args);
}
/**
* # JMH version: 1.21
* # VM version: JDK 1.8.0_265, OpenJDK 64-Bit Server VM, 25.265-b01
* # VM invoker: /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/bin/java
* # VM options: -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=61104:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8
* # Warmup: 5 iterations, 10 s each
* # Measurement: 5 iterations, 10 s each
* # Timeout: 10 min per iteration
* # Threads: 1 thread, will synchronize iterations
* # Benchmark mode: Sampling time
*
* Benchmark Mode Cnt Score Error Units
* LoggingBenchmark.jsonLogger sample 1400812 2305.088 ± 19.119 ns/op
* LoggingBenchmark.jsonLogger:jsonLogger·p0.00 sample 1988.000 ns/op
* LoggingBenchmark.jsonLogger:jsonLogger·p0.50 sample 2156.000 ns/op
* LoggingBenchmark.jsonLogger:jsonLogger·p0.90 sample 2280.000 ns/op
* LoggingBenchmark.jsonLogger:jsonLogger·p0.95 sample 2388.000 ns/op
* LoggingBenchmark.jsonLogger:jsonLogger·p0.99 sample 3576.000 ns/op
* LoggingBenchmark.jsonLogger:jsonLogger·p0.999 sample 18688.000 ns/op
* LoggingBenchmark.jsonLogger:jsonLogger·p0.9999 sample 78072.717 ns/op
* LoggingBenchmark.jsonLogger:jsonLogger·p1.00 sample 1183744.000 ns/op
* LoggingBenchmark.patternLogger sample 1100999 1522.612 ± 23.720 ns/op
* LoggingBenchmark.patternLogger:patternLogger·p0.00 sample 1270.000 ns/op
* LoggingBenchmark.patternLogger:patternLogger·p0.50 sample 1378.000 ns/op
* LoggingBenchmark.patternLogger:patternLogger·p0.90 sample 1452.000 ns/op
* LoggingBenchmark.patternLogger:patternLogger·p0.95 sample 1548.000 ns/op
* LoggingBenchmark.patternLogger:patternLogger·p0.99 sample 2188.000 ns/op
* LoggingBenchmark.patternLogger:patternLogger·p0.999 sample 17696.000 ns/op
* LoggingBenchmark.patternLogger:patternLogger·p0.9999 sample 589721.600 ns/op
* LoggingBenchmark.patternLogger:patternLogger·p1.00 sample 1259520.000 ns/op
*/
}
......@@ -25,11 +25,11 @@ import org.hamcrest.core.StringContains;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import java.util.List;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.times;
public class PatternLoggerTest {
......@@ -57,18 +57,38 @@ public class PatternLoggerTest {
Assert.assertTrue(logger.isWarnEnable());
Assert.assertTrue(logger.isErrorEnable());
ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
logger.debug("hello world");
Mockito.verify(output, times(1)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("DEBUG [testAppFromConfig,,,] [main] PatternLoggerTest:-1 hello world"));
logger.debug("hello {}", "world");
Mockito.verify(output, times(2)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("DEBUG [testAppFromConfig,,,] [main] PatternLoggerTest:-1 hello world"));
logger.info("hello world");
Mockito.verify(output, times(3)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("INFO [testAppFromConfig,,,] [main] PatternLoggerTest:-1 hello world"));
logger.info("hello {}", "world");
Mockito.verify(output, times(4)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("INFO [testAppFromConfig,,,] [main] PatternLoggerTest:-1 hello world"));
logger.warn("hello {}", "world");
Mockito.verify(output, times(5)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("WARN [testAppFromConfig,,,] [main] PatternLoggerTest:-1 hello world"));
logger.warn("hello world");
Mockito.verify(output, times(6)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("WARN [testAppFromConfig,,,] [main] PatternLoggerTest:-1 hello world"));
logger.error("hello world");
Mockito.verify(output, times(7)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("ERROR [testAppFromConfig,,,] [main] PatternLoggerTest:-1 hello world"));
logger.error("hello world", new NullPointerException());
Mockito.verify(output, times(8)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("ERROR [testAppFromConfig,,,] [main] PatternLoggerTest:-1 hello world"));
Assert.assertThat(argument.getValue(), StringContains.containsString("java.lang.NullPointerException"));
logger.error(new NullPointerException(), "hello {}", "world");
Mockito.verify(output, times(9)).write(anyString());
Mockito.verify(output, times(9)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("java.lang.NullPointerException"));
}
@Test
......@@ -86,18 +106,37 @@ public class PatternLoggerTest {
Assert.assertTrue(logger.isWarnEnable());
Assert.assertTrue(logger.isErrorEnable());
ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
logger.debug("$^!@#*()");
Mockito.verify(output, times(1)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("DEBUG [testAppFromConfig,,,] [main] PatternLoggerTest:-1 $^!@#*()"));
logger.debug("hello {}", "!@#$%^&*(),./[]:;");
Mockito.verify(output, times(2)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("DEBUG [testAppFromConfig,,,] [main] PatternLoggerTest:-1 hello !@#$%^&*(),./[]:;"));
logger.info("{}{}");
Mockito.verify(output, times(3)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("INFO [testAppFromConfig,,,] [main] PatternLoggerTest:-1 {}{}"));
logger.info("hello {}", "{}{}");
Mockito.verify(output, times(4)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("INFO [testAppFromConfig,,,] [main] PatternLoggerTest:-1 hello {}{}"));
logger.warn("hello {}", "\\");
Mockito.verify(output, times(5)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("WARN [testAppFromConfig,,,] [main] PatternLoggerTest:-1 hello \\"));
logger.warn("hello \\");
Mockito.verify(output, times(6)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("WARN [testAppFromConfig,,,] [main] PatternLoggerTest:-1 hello \\"));
logger.error("hello <>..");
Mockito.verify(output, times(7)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("ERROR [testAppFromConfig,,,] [main] PatternLoggerTest:-1 hello <>.."));
logger.error("hello ///\\\\", new NullPointerException());
Mockito.verify(output, times(8)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("ERROR [testAppFromConfig,,,] [main] PatternLoggerTest:-1 hello ///\\\\"));
logger.error(new NullPointerException(), "hello {}", "&&&**%%");
Mockito.verify(output, times(9)).write(anyString());
Mockito.verify(output, times(9)).write(argument.capture());
Assert.assertThat(argument.getValue(), StringContains.containsString("ERROR [testAppFromConfig,,,] [main] PatternLoggerTest:-1 hello &&&**%%"));
}
@Test
......
......@@ -20,6 +20,7 @@ package org.apache.skywalking.apm.agent;
import java.lang.instrument.Instrumentation;
import java.util.List;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.NamedElement;
......@@ -53,7 +54,7 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
* The main entrance of sky-walking agent, based on javaagent mechanism.
*/
public class SkyWalkingAgent {
private static final ILog LOGGER = LogManager.getLogger(SkyWalkingAgent.class);
private static ILog LOGGER = LogManager.getLogger(SkyWalkingAgent.class);
/**
* Main entrance. Use byte-buddy transform to enhance all classes, which define in plugins.
......@@ -62,7 +63,17 @@ public class SkyWalkingAgent {
final PluginFinder pluginFinder;
try {
SnifferConfigInitializer.initializeCoreConfig(agentArgs);
} catch (Exception e) {
// try to resolve a new logger, and use the new logger to write the error log here
LogManager.getLogger(SkyWalkingAgent.class)
.error(e, "SkyWalking agent initialized failure. Shutting down.");
return;
} finally {
// refresh logger again after initialization finishes
LOGGER = LogManager.getLogger(SkyWalkingAgent.class);
}
try {
pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins());
} catch (AgentPackageNotFoundException ape) {
LOGGER.error(ape, "Locate agent.jar failure. Shutting down.");
......@@ -75,14 +86,15 @@ public class SkyWalkingAgent {
final ByteBuddy byteBuddy = new ByteBuddy().with(TypeValidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS));
AgentBuilder agentBuilder = new AgentBuilder.Default(byteBuddy).ignore(
nameStartsWith("net.bytebuddy.").or(nameStartsWith("org.slf4j."))
.or(nameStartsWith("org.groovy."))
.or(nameContains("javassist"))
.or(nameContains(".asm."))
.or(nameContains(".reflectasm."))
.or(nameStartsWith("sun.reflect"))
.or(allSkyWalkingAgentExcludeToolkit())
.or(ElementMatchers.isSynthetic()));
nameStartsWith("net.bytebuddy.")
.or(nameStartsWith("org.slf4j."))
.or(nameStartsWith("org.groovy."))
.or(nameContains("javassist"))
.or(nameContains(".asm."))
.or(nameContains(".reflectasm."))
.or(nameStartsWith("sun.reflect"))
.or(allSkyWalkingAgentExcludeToolkit())
.or(ElementMatchers.isSynthetic()));
JDK9ModuleExporter.EdgeClasses edgeClasses = new JDK9ModuleExporter.EdgeClasses();
try {
......@@ -121,7 +133,7 @@ public class SkyWalkingAgent {
}
Runtime.getRuntime()
.addShutdownHook(new Thread(ServiceManager.INSTANCE::shutdown, "skywalking service shutdown thread"));
.addShutdownHook(new Thread(ServiceManager.INSTANCE::shutdown, "skywalking service shutdown thread"));
}
private static class Transformer implements AgentBuilder.Transformer {
......@@ -142,7 +154,7 @@ public class SkyWalkingAgent {
EnhanceContext context = new EnhanceContext();
for (AbstractClassEnhancePluginDefine define : pluginDefines) {
DynamicType.Builder<?> possibleNewBuilder = define.define(
typeDescription, newBuilder, classLoader, context);
typeDescription, newBuilder, classLoader, context);
if (possibleNewBuilder != null) {
newBuilder = possibleNewBuilder;
}
......
......@@ -42,6 +42,12 @@
<version>${solr-solrj.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
......@@ -47,5 +47,10 @@
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
......@@ -96,7 +96,8 @@ property key | Description | Default |
`logging.file_name`|Log file name.|`skywalking-api.log`|
`logging.output`| Log output. Default is FILE. Use CONSOLE means output to stdout. |`FILE`|
`logging.dir`|Log files directory. Default is blank string, means, use "{theSkywalkingAgentJarDir}/logs " to output logs. {theSkywalkingAgentJarDir} is the directory where the skywalking agent jar file is located |`""`|
`logging.pattern `|logging format. There are all conversion specifiers: <br>&nbsp;&nbsp;* `%level` means log level. <br>&nbsp;&nbsp;* `%timestamp` means now of time with format `yyyy-MM-dd HH:mm:ss:SSS`.<br>&nbsp;&nbsp;* `%thread` means name of current thread.<br>&nbsp;&nbsp;* `%msg` means some message which user logged. <br>&nbsp;&nbsp;* `%class` means SimpleName of TargetClass. <br>&nbsp;&nbsp;* `%throwable` means a throwable which user called. <br>&nbsp;&nbsp;* `%agent_name` means `agent.service_name` |`%level %timestamp %thread %class : %msg %throwable`|
`logging.resolver`|Logger resolver: `PATTERN` or `JSON`. The default is `PATTERN`, which uses `logging.pattern` to print traditional text logs. `JSON` resolver prints logs in JSON format. |`PATTERN`|
`logging.pattern `|Logging format. There are all conversion specifiers: <br>&nbsp;&nbsp;* `%level` means log level. <br>&nbsp;&nbsp;* `%timestamp` means now of time with format `yyyy-MM-dd HH:mm:ss:SSS`.<br>&nbsp;&nbsp;* `%thread` means name of current thread.<br>&nbsp;&nbsp;* `%msg` means some message which user logged. <br>&nbsp;&nbsp;* `%class` means SimpleName of TargetClass. <br>&nbsp;&nbsp;* `%throwable` means a throwable which user called. <br>&nbsp;&nbsp;* `%agent_name` means `agent.service_name`. Only apply to the `PatternLogger`. |`%level %timestamp %thread %class : %msg %throwable`|
`logging.max_file_size`|The max size of log file. If the size is bigger than this, archive the current file, and write into a new file.|`300 * 1024 * 1024`|
`logging.max_history_files`|The max history log files. When rollover happened, if log files exceed this number,then the oldest file will be delete. Negative or zero means off, by default.|`-1`|
`jvm.buffer_size`|The buffer size of collected JVM info.|`60 * 10`|
......
......@@ -250,6 +250,7 @@
<version>${jmh.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
......@@ -290,6 +291,12 @@
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
......@@ -588,7 +595,9 @@
org/apache/skywalking/oap/server/core/remote/grpc/proto/*.java,
org/apache/skywalking/oal/rt/grammar/*.java,
org/apache/skywalking/oap/server/exporter/grpc/*.java,
org/apache/skywalking/oap/server/configuration/service/*.java
org/apache/skywalking/oap/server/configuration/service/*.java,
**/generated/*_jmhType*.java,
**/generated/*_jmhTest.java
</excludes>
<propertyExpansion>
import.control=apm-checkstyle/importControl.xml
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册