提交 ffe1df57 编写于 作者: A Alvin 提交者: wu-sheng

Enhance agent logger. (#3250)

* Add pattern logger to replace the easy logger.
* Doc update
* Support console log 
上级 fc026ec3
......@@ -31,4 +31,5 @@ public class PlaceholderConfigurerSupport {
/** Default value separator: {@value} */
public static final String DEFAULT_VALUE_SEPARATOR = ":";
}
......@@ -21,6 +21,7 @@ package org.apache.skywalking.apm.agent.core.conf;
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.WriterFactory;
import java.util.HashMap;
......@@ -169,6 +170,28 @@ public class Config {
* The log level. Default is debug.
*/
public static LogLevel LEVEL = LogLevel.DEBUG;
/**
* The log output. Default is FILE.
*/
public static LogOutput OUTPUT = LogOutput.FILE;
/**
* 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 specifiers:
* %thread = ThreadName
* %level = LogLevel {@link LogLevel}
* %timestamp = The now() who format is 'yyyy-MM-dd HH:mm:ss:SSS'
* %class = SimpleName of TargetClass
* %msg = Message of user input
* %throwable = Throwable of user input
* %agent_name = ServiceName of Agent {@link Agent#SERVICE_NAME}
*
* @see org.apache.skywalking.apm.agent.core.logging.core.PatternLogger#DEFAULT_CONVERTER_MAP
*
*/
public static String PATTERN = "%level %timestamp %thread %class : %msg %throwable";
}
public static class Plugin {
......
......@@ -19,7 +19,7 @@
package org.apache.skywalking.apm.agent.core.logging.api;
import org.apache.skywalking.apm.agent.core.logging.core.EasyLogResolver;
import org.apache.skywalking.apm.agent.core.logging.core.PatternLogResolver;
/**
* LogManager is the {@link LogResolver} implementation manager. By using {@link LogResolver}, {@link
......@@ -34,7 +34,7 @@ import org.apache.skywalking.apm.agent.core.logging.core.EasyLogResolver;
* <p> Created by xin on 2016/11/10.
*/
public class LogManager {
private static LogResolver RESOLVER = new EasyLogResolver();
private static LogResolver RESOLVER = new PatternLogResolver();
public static void setLogResolver(LogResolver resolver) {
LogManager.RESOLVER = resolver;
......
/*
* 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;
/**
* The Converter, It is used to convert the LogEvent to the String.
* @author alvin
*/
public interface Converter {
String convert(LogEvent logEvent);
}
/*
* 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;
/**
* The representation of logging events. This instance is pass around to the List of Converter.
*
* @author alvin
*/
public class LogEvent {
public LogEvent(LogLevel level, String message, Throwable throwable, String targetClass) {
this.level = level;
this.message = message;
this.throwable = throwable;
this.targetClass = targetClass;
}
private LogLevel level;
private String message;
private Throwable throwable;
private String targetClass;
public String getTargetClass() {
return targetClass;
}
public void setTargetClass(String targetClass) {
this.targetClass = targetClass;
}
public LogLevel getLevel() {
return level;
}
public void setLevel(LogLevel level) {
this.level = level;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Throwable getThrowable() {
return throwable;
}
public void setThrowable(Throwable throwable) {
this.throwable = 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;
/**
* @author alvin
*/
public enum LogOutput {
FILE, CONSOLE
}
/*
* 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.logging.core.coverts.LiteralConverter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Parser of LogPattern. It is used to parse a pattern to the List of Converter.
* @author alvin
*/
public class Parser {
private final Map<String, Class<? extends Converter>> convertMaps;
enum State {
LITERAL_STATE, KEYWORD_STATE
}
public static final char ESCAPE_CHAR = '\\';
public static final char PERCENT_CHAR = '%';
private final String pattern;
private final int patternLength;
private int pointer = 0;
private State state = State.LITERAL_STATE;
public Parser(String pattern, Map<String, Class<? extends Converter>> convertMaps) {
if (pattern == null || pattern.length() == 0) {
throw new IllegalArgumentException("null or empty pattern string not allowed");
}
this.convertMaps = convertMaps;
this.pattern = pattern;
this.patternLength = pattern.length();
}
public List<Converter> parse() {
List<Converter> patternConverters = new ArrayList<Converter>();
StringBuilder buf = new StringBuilder();
while (pointer < patternLength) {
char c = pattern.charAt(pointer);
pointer++;
switch (state) {
case LITERAL_STATE:
handleLiteralState(c, buf, patternConverters);
break;
case KEYWORD_STATE:
handleKeywordState(c, buf, patternConverters);
break;
default:
}
}
switch (state) {
case LITERAL_STATE:
addConverter(buf, patternConverters, LiteralConverter.class);
break;
case KEYWORD_STATE:
addConverterWithKeyword(buf, patternConverters);
break;
default:
}
return combineLiteral(patternConverters);
}
private List<Converter> combineLiteral(List<Converter> patternConverters) {
List<Converter> converterList = new ArrayList<Converter>();
StringBuilder stringBuilder = new StringBuilder();
for (Converter patternConverter : patternConverters) {
if (patternConverter instanceof LiteralConverter) {
stringBuilder.append(patternConverter.convert(null));
} else {
if (stringBuilder.length() > 0) {
converterList.add(new LiteralConverter(stringBuilder.toString()));
stringBuilder.setLength(0);
}
converterList.add(patternConverter);
}
}
return converterList;
}
private void handleKeywordState(char c, StringBuilder buf, List<Converter> patternConverters) {
if (Character.isJavaIdentifierPart(c)) {
buf.append(c);
} else if (c == PERCENT_CHAR) {
addConverterWithKeyword(buf, patternConverters);
} else {
addConverterWithKeyword(buf, patternConverters);
if (c == ESCAPE_CHAR) {
escape("%", buf);
} else {
buf.append(c);
}
state = State.LITERAL_STATE;
}
}
private void addConverterWithKeyword(StringBuilder buf, List<Converter> patternConverters) {
String keyword = buf.toString();
if (convertMaps.containsKey(keyword)) {
addConverter(buf, patternConverters, convertMaps.get(keyword));
} else {
buf.insert(0, "%");
addConverter(buf, patternConverters, LiteralConverter.class);
}
}
private void handleLiteralState(char c, StringBuilder buf, List<Converter> patternConverters) {
switch (c) {
case ESCAPE_CHAR:
escape("%", buf);
break;
case PERCENT_CHAR:
addConverter(buf, patternConverters, LiteralConverter.class);
state = State.KEYWORD_STATE;
break;
default:
buf.append(c);
}
}
private void escape(String escapeChars, StringBuilder buf) {
if (pointer < patternLength) {
char next = pattern.charAt(pointer++);
escape(escapeChars, buf, next);
}
}
private void addConverter(StringBuilder buf, List<Converter> patternConverters, Class<? extends Converter> aClass) {
if (buf.length() > 0) {
String result = buf.toString();
if (LiteralConverter.class.equals(aClass)) {
patternConverters.add(new LiteralConverter(result));
} else {
try {
patternConverters.add(aClass.newInstance());
} catch (Exception e) {
throw new IllegalStateException("Create Converter error. Class: " + aClass, e);
}
}
buf.setLength(0);
}
}
private void escape(String escapeChars, StringBuilder buf, char next) {
if (escapeChars.indexOf(next) >= 0) {
buf.append(next);
} else {
switch (next) {
case '_':
// the \_ sequence is swallowed
break;
case '\\':
buf.append(next);
break;
case 't':
buf.append('\t');
break;
case 'r':
buf.append('\r');
break;
case 'n':
buf.append('\n');
break;
default:
throw new IllegalArgumentException("Illegal char " + next + ". It not allowed as escape characters.");
}
}
}
}
......@@ -19,19 +19,22 @@
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.api.LogResolver;
/**
* Created by wusheng on 2016/11/26.
* @author alvin
*/
public class EasyLogResolver implements LogResolver {
public class PatternLogResolver implements LogResolver {
@Override
public ILog getLogger(Class<?> clazz) {
return new EasyLogger(clazz);
return new PatternLogger(clazz, Config.Logging.PATTERN);
}
@Override public ILog getLogger(String clazz) {
return new EasyLogger(clazz);
@Override
public ILog getLogger(String clazz) {
return new PatternLogger(clazz, Config.Logging.PATTERN);
}
}
......@@ -16,36 +16,75 @@
*
*/
package org.apache.skywalking.apm.agent.core.logging.core;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Matcher;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.conf.Constants;
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;
/**
* The <code>EasyLogger</code> is a simple implementation of {@link ILog}.
* 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.
*
* @author wusheng
* @author alvin
*/
public class EasyLogger implements ILog {
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 static final String DEFAULT_PATTERN = "%level %timestamp %thread %class : %msg %throwable";
private String pattern;
private List<Converter> converters;
private String targetClass;
public EasyLogger(Class targetClass) {
this.targetClass = targetClass.getSimpleName();
public PatternLogger(Class targetClass, String pattern) {
this(targetClass.getSimpleName(), pattern);
}
public EasyLogger(String targetClass) {
public PatternLogger(String targetClass, String pattern) {
this.targetClass = targetClass;
this.setPattern(pattern);
}
public String getPattern() {
return pattern;
}
public void setPattern(String pattern) {
if (StringUtil.isEmpty(pattern)) {
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));
}
......@@ -68,30 +107,6 @@ public class EasyLogger implements ILog {
return tmpMessage;
}
String format(LogLevel level, String message, Throwable t) {
return StringUtil.join(' ', level.name(),
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(new Date()),
Thread.currentThread().getName(),
targetClass,
": ",
message,
t == null ? "" : format(t)
);
}
String format(Throwable t) {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
t.printStackTrace(new java.io.PrintWriter(buf, true));
String expMessage = buf.toString();
try {
buf.close();
} catch (IOException e) {
e.printStackTrace();
}
return Constants.LINE_SEPARATOR + expMessage;
}
@Override
public void info(String format) {
if (isInfoEnable())
......@@ -168,4 +183,14 @@ public class EasyLogger implements ILog {
logger(LogLevel.ERROR, format, null);
}
}
String format(LogLevel level, String message, Throwable t) {
LogEvent logEvent = new LogEvent(level, message, t, targetClass);
StringBuilder stringBuilder = new StringBuilder();
for (Converter converter : converters) {
stringBuilder.append(converter.convert(logEvent));
}
return stringBuilder.toString();
}
}
......@@ -27,7 +27,7 @@ import org.apache.skywalking.apm.util.StringUtil;
public class WriterFactory {
public static IWriter getLogWriter() {
if (SnifferConfigInitializer.isInitCompleted() && AgentPackagePath.isPathFound()) {
if (!useConsole() && SnifferConfigInitializer.isInitCompleted() && AgentPackagePath.isPathFound()) {
if (StringUtil.isEmpty(Config.Logging.DIR)) {
try {
Config.Logging.DIR = AgentPackagePath.getPath() + "/logs";
......@@ -40,4 +40,8 @@ public class WriterFactory {
return SystemOutWriter.INSTANCE;
}
}
private static boolean useConsole() {
return LogOutput.CONSOLE == Config.Logging.OUTPUT;
}
}
/*
* 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.coverts;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.logging.core.Converter;
import org.apache.skywalking.apm.agent.core.logging.core.LogEvent;
/**
*
* @author alvin
*/
public class AgentNameConverter implements Converter {
@Override
public String convert(LogEvent logEvent) {
return Config.Agent.SERVICE_NAME;
}
}
/*
* 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.coverts;
import org.apache.skywalking.apm.agent.core.logging.core.Converter;
import org.apache.skywalking.apm.agent.core.logging.core.LogEvent;
/**
* Just return logEvent.getTargetClass().
* @author alvin
*/
public class ClassConverter implements Converter {
@Override
public String convert(LogEvent logEvent) {
return logEvent.getTargetClass();
}
}
/*
* 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.coverts;
import org.apache.skywalking.apm.agent.core.logging.core.Converter;
import org.apache.skywalking.apm.agent.core.logging.core.LogEvent;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* The Converter is used to return a now date with format.
*
* @author alvin
*/
public class DateConverter implements Converter {
@Override
public String convert(LogEvent logEvent) {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(new Date());
}
}
/*
* 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.coverts;
import org.apache.skywalking.apm.agent.core.logging.core.Converter;
import org.apache.skywalking.apm.agent.core.logging.core.LogEvent;
/**
* Just return logEvent.getLevel().name()
* @author alvin
*/
public class LevelConverter implements Converter {
@Override
public String convert(LogEvent logEvent) {
return logEvent.getLevel().name();
}
}
/*
* 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.coverts;
import org.apache.skywalking.apm.agent.core.logging.core.Converter;
import org.apache.skywalking.apm.agent.core.logging.core.LogEvent;
/**
* This Converter is used to return the literal.
* @author alvin
*/
public class LiteralConverter implements Converter {
private final String literal;
public LiteralConverter(String literal) {
this.literal = literal;
}
@Override
public String convert(LogEvent logEvent) {
return literal;
}
}
/*
* 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.coverts;
import org.apache.skywalking.apm.agent.core.logging.core.Converter;
import org.apache.skywalking.apm.agent.core.logging.core.LogEvent;
/**
* Just return the logEvent.getMessage()
* @author alvin
*/
public class MessageConverter implements Converter {
@Override
public String convert(LogEvent logEvent) {
return logEvent.getMessage();
}
}
/*
* 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.coverts;
import org.apache.skywalking.apm.agent.core.logging.core.Converter;
import org.apache.skywalking.apm.agent.core.logging.core.LogEvent;
/**
* Just return the Thread.currentThread().getName()
* @author alvin
*/
public class ThreadConverter implements Converter {
@Override
public String convert(LogEvent logEvent) {
return Thread.currentThread().getName();
}
}
/*
* 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.coverts;
import org.apache.skywalking.apm.agent.core.conf.Constants;
import org.apache.skywalking.apm.agent.core.logging.core.Converter;
import org.apache.skywalking.apm.agent.core.logging.core.LogEvent;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* Return the StackTrace of String with logEvent.getThrowable()
* @author alvin
*/
public class ThrowableConverter implements Converter {
@Override
public String convert(LogEvent logEvent) {
Throwable t = logEvent.getThrowable();
return t == null ? "" : format(t);
}
public static String format(Throwable t) {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
t.printStackTrace(new java.io.PrintWriter(buf, true));
String expMessage = buf.toString();
try {
buf.close();
} catch (IOException e) {
e.printStackTrace();
}
return Constants.LINE_SEPARATOR + expMessage;
}
}
......@@ -23,11 +23,13 @@ import org.junit.Assert;
import org.junit.Test;
/**
* Created by wusheng on 2017/2/28.
* @author alvin
*/
public class EasyLogResolverTest {
public class PatternLogResolverTest {
@Test
public void testGetLogger() {
Assert.assertTrue(new EasyLogResolver().getLogger(EasyLogResolverTest.class) instanceof EasyLogger);
Assert.assertTrue(new PatternLogResolver().getLogger(PatternLoggerTest.class) instanceof PatternLogger);
}
}
}
\ No newline at end of file
......@@ -19,22 +19,29 @@
package org.apache.skywalking.apm.agent.core.logging.core;
import com.google.common.collect.Lists;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.conf.Constants;
import org.hamcrest.core.StringContains;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
import org.apache.skywalking.apm.agent.core.conf.Constants;
import java.io.PrintStream;
import java.util.List;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.times;
/**
* Created by wusheng on 2017/2/28.
* @author alvin
*/
public class EasyLoggerTest {
public class PatternLoggerTest {
public static final String PATTERN = "%timestamp+0800 %level [%agent_name,,,] [%thread] %class:-1 %msg %throwable";
private static PrintStream OUT_REF;
private static PrintStream ERR_REF;
......@@ -42,18 +49,21 @@ public class EasyLoggerTest {
public static void initAndHoldOut() {
OUT_REF = System.out;
ERR_REF = System.err;
Config.Agent.SERVICE_NAME = "testAppFromConfig";
}
@Test
public void testLog() {
PrintStream output = Mockito.mock(PrintStream.class);
System.setOut(output);
PrintStream err = Mockito.mock(PrintStream.class);
System.setErr(err);
EasyLogger logger = new EasyLogger(EasyLoggerTest.class) {
PatternLogger logger = new PatternLogger(PatternLoggerTest.class, PATTERN) {
@Override
protected void logger(LogLevel level, String message, Throwable e) {
SystemOutWriter.INSTANCE.write(format(level, message, e));
String r = format(level, message, e);
SystemOutWriter.INSTANCE.write(r);
}
};
......@@ -83,7 +93,7 @@ public class EasyLoggerTest {
System.setOut(output);
PrintStream err = Mockito.mock(PrintStream.class);
System.setErr(err);
EasyLogger logger = new EasyLogger(EasyLoggerTest.class) {
PatternLogger logger = new PatternLogger(PatternLoggerTest.class, PATTERN) {
@Override
protected void logger(LogLevel level, String message, Throwable e) {
SystemOutWriter.INSTANCE.write(format(level, message, e));
......@@ -111,18 +121,45 @@ public class EasyLoggerTest {
}
@Test
public void testFormat() {
public void testLogOk_whenPatternHasKeyword() {
final List<String> strings = Lists.newArrayList();
PatternLogger logger = new PatternLogger(PatternLoggerTest.class, "logmsg: %%%%%%!@#$\\%^&*() %{this is message} \\\\ \\n\\t \t\n %%msg") {
@Override
protected void logger(LogLevel level, String message, Throwable e) {
String r = format(level, message, e);
strings.add(r);
}
};
logger.info("msg");
Assert.assertThat(strings.get(0), StringContains.containsString("logmsg: %%%%%%!@#$%^&*() %{this is message} \\ \n\t \t\n %msg"));
}
@Test
public void testLogFormat() {
final List<String> strings = Lists.newArrayList();
PatternLogger logger = new PatternLogger(PatternLoggerTest.class, PATTERN) {
@Override
protected void logger(LogLevel level, String message, Throwable e) {
String r = format(level, message, e);
strings.add(r);
}
};
NullPointerException exception = new NullPointerException();
EasyLogger logger = new EasyLogger(EasyLoggerTest.class);
String formatLines = logger.format(exception);
logger.error("hello world", exception);
logger.error("hello world", null);
String formatLines = strings.get(0);
String[] lines = formatLines.split(Constants.LINE_SEPARATOR);
Assert.assertThat(lines[0], StringContains.containsString("ERROR [testAppFromConfig,,,] [main] PatternLoggerTest:-1 hello world "));
Assert.assertEquals("java.lang.NullPointerException", lines[1]);
Assert.assertEquals("\tat org.apache.skywalking.apm.agent.core.logging.core.EasyLoggerTest.testFormat(EasyLoggerTest.java:115)", lines[2]);
Assert.assertThat(lines[2], StringContains.containsString("PatternLoggerTest.testLogFormat"));
Assert.assertEquals(strings.get(1).split(Constants.LINE_SEPARATOR).length, 1);
}
@AfterClass
public static void reset() {
System.setOut(OUT_REF);
System.setErr(ERR_REF);
}
}
/*
* 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.boot.AgentPackagePath;
import org.apache.skywalking.apm.agent.core.conf.Config;
import org.apache.skywalking.apm.agent.core.conf.SnifferConfigInitializer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.BDDMockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.junit.Assert.assertTrue;
@RunWith(PowerMockRunner.class)
@PrepareForTest(value = {SnifferConfigInitializer.class, AgentPackagePath.class})
public class WriterFactoryTest {
@Test
public void alwaysReturnSystemLogWriteWithSetLoggingDir() {
Config.Logging.OUTPUT = LogOutput.CONSOLE;
PowerMockito.mockStatic(SnifferConfigInitializer.class);
PowerMockito.mockStatic(AgentPackagePath.class);
BDDMockito.given(SnifferConfigInitializer.isInitCompleted()).willReturn(true);
BDDMockito.given(AgentPackagePath.isPathFound()).willReturn(true);
assertTrue(SnifferConfigInitializer.isInitCompleted());
assertTrue(AgentPackagePath.isPathFound());
IWriter logWriter = WriterFactory.getLogWriter();
PowerMockito.verifyStatic();
assertTrue(logWriter instanceof SystemOutWriter);
}
@Test
public void returnFileWriterWriteWithBlankLoggingDir() {
Config.Logging.OUTPUT = LogOutput.FILE;
PowerMockito.mockStatic(SnifferConfigInitializer.class);
PowerMockito.mockStatic(AgentPackagePath.class);
BDDMockito.given(SnifferConfigInitializer.isInitCompleted()).willReturn(true);
BDDMockito.given(AgentPackagePath.isPathFound()).willReturn(true);
assertTrue(SnifferConfigInitializer.isInitCompleted());
assertTrue(AgentPackagePath.isPathFound());
IWriter logWriter = WriterFactory.getLogWriter();
PowerMockito.verifyStatic();
assertTrue(logWriter instanceof FileWriter);
}
}
\ No newline at end of file
......@@ -82,7 +82,9 @@ property key | Description | Default |
`collector.backend_service`|Collector SkyWalking trace receiver service addresses.|`127.0.0.1:11800`|
`logging.level`|The log level. Default is debug.|`DEBUG`|
`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 "system.out" to output logs.|`""`|
`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.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`|
`jvm.buffer_size`|The buffer size of collected JVM info.|`60 * 10`|
`buffer.channel_size`|The buffer channel size.|`5`|
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册