日志管理
GaussDB JDBC驱动程序支持使用日志记录来帮助解决在应用程序中使用GaussDB JDBC驱动程序时的问题。GaussDB JDBC支持如下两种日志管理方式:
- 对接应用程序使用的SLF4J日志框架。
- 对接应用程序使用的JdkLogger日志框架。
SLF4J和JdkLogger是业界Java应用程序日志管理的主流框架,描述应用程序如何使用这些框架超出了本文范围,用户请参考对应的官方文档(SLF4J:http://www.slf4j.org/manual.html,JdkLogger:https://docs.oracle.com/javase/8/docs/technotes/guides/logging/overview.html)。
方式一:对接应用程序的SLF4J日志框架。
在建立连接时,url配置logger=Slf4JLogger。
可采用Log4j或Log4j2来实现SLF4J。当采用Log4j实现SLF4J,需要添加如下jar包:log4j-*.jar、slf4j-api-*.jar、slf4j-log4*-*.jar,(*区分版本),和配置文件:log4j.properties。并且在主程序中添加读配置文件的代码。若采用Log4j2实现SLF4J,需要添加如下jar包:log4j-api-*.jar、log4j-core-*.jar、log4j-slf4j18-impl-*.jar、slf4j-api-*-alpha1.jar(*区分版本),和配置文件:log4j2.xml。
此方式支持日志管控。SLF4J可通过文件中的相关配置实现强大的日志管控功能,建议使用此方式进行日志管理。
示例:
//注意:调用时需要指定log4j.propertie或者log4j2.xml文件位置。 //指定log4j.propertie位置。 //PropertyConfigurator.configure("log4j.properties"); //指定log4j2.xml。 //ConfigurationSource source = new ConfigurationSource(new FileInputStream("log4j2.xml")); //Configurator.initialize(null, source); public static Connection GetConnection(String username, String passwd){ String sourceURL = "jdbc:gaussdb://$ip:$port/database?logger=Slf4JLogger"; Connection conn = null; try{ //创建连接。 conn = DriverManager.getConnection(sourceURL,username,passwd); System.out.println("Connection succeed!"); }catch (Exception e){ e.printStackTrace(); return null; } return conn; }
log4j.properties示例:
log4j.logger.com.huawei.gaussdb.jdbc=ALL, log_gsjdbc # 默认文件输出配置。 log4j.appender.log_gsjdbc=org.apache.log4j.RollingFileAppender log4j.appender.log_gsjdbc.Append=true log4j.appender.log_gsjdbc.File=gsjdbc.log log4j.appender.log_gsjdbc.Threshold=TRACE log4j.appender.log_gsjdbc.MaxFileSize=10MB log4j.appender.log_gsjdbc.MaxBackupIndex=5 log4j.appender.log_gsjdbc.layout=org.apache.log4j.PatternLayout log4j.appender.log_gsjdbc.layout.ConversionPattern=%d %p %t %c - %m%n log4j.appender.log_gsjdbc.File.Encoding = UTF-8
log4j2.xml示例:
<?xml version="1.0" encoding="UTF-8"?> <configuration status="OFF"> <appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d %p %t %c - %m%n"/> </Console> <File name="FileTest" fileName="test.log"> <PatternLayout pattern="%d %p %t %c - %m%n"/> </File> <!--JDBC Driver日志文件输出配置,支持日志回卷,设定日志大小超过10MB时,创建新的文件,新文件的命名格式为:年-月-日-文件编号--> <RollingFile name="RollingFileJdbc" fileName="gsjdbc.log" filePattern="%d{yyyy-MM-dd}-%i.log"> <PatternLayout pattern="%d %p %t %c - %m%n"/> <Policies> <SizeBasedTriggeringPolicy size="10 MB"/> </Policies> </RollingFile> </appenders> <loggers> <root level="all"> <appender-ref ref="Console"/> <appender-ref ref="FileTest"/> </root> <!--指定JDBC Driver日志,级别为:all,可查看所有日志,输出到gsjdbc.log文件中--> <logger name="com.huawei.gaussdb.jdbc.Driver" level="all" additivity="false"> <appender-ref ref="RollingFileJdbc"/> </logger> </loggers> </configuration>
- 在配置文件中,可以指定JDBC与上层业务的配置路径,将JDBC日志与业务日志分别存储到不同文件。
- 同一个项目中配置多个GaussDB数据源时,如果存在部分业务配置了logger=Slf4JLogger,部分业务未配置,会互相影响日志配置。建议这种情况下连接串统一配置。
方式二:对接应用程序使用的JdkLogger日志框架。
默认的Java日志记录框架将其配置存储在名为logging.properties的文件中。Java会在Java安装目录的文件夹中安装全局配置文件。logging.properties文件也可以创建并与单个项目一起存储。
logging.properties配置示例:
# 指定处理程序为文件。 handlers= java.util.logging.FileHandler # 指定默认全局日志级别。 .level= ALL # 指定日志输出管控标准。 java.util.logging.FileHandler.level=ALL java.util.logging.FileHandler.pattern = gsjdbc.log java.util.logging.FileHandler.limit = 500000 java.util.logging.FileHandler.count = 30 java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter java.util.logging.FileHandler.append=false
System.setProperty("java.util.logging.FileHandler.pattern","jdbc.log"); FileHandler fileHandler = new FileHandler(System.getProperty("java.util.logging.FileHandler.pattern")); Formatter formatter = new SimpleFormatter(); fileHandler.setFormatter(formatter); Logger logger = Logger.getLogger("com.huawei.gaussdb.jdbc"); logger.addHandler(fileHandler); logger.setLevel(Level.ALL); logger.setUseParentHandlers(false);
链路跟踪功能
GaussDB JDBC驱动程序提供了应用到数据库的链路跟踪功能,用于将数据库端离散的SQL和应用程序的请求关联起来。该功能需要应用开发者实现com.huawei.gaussdb.jdbc.log.Tracer接口类,并在url中指定接口实现类的权限定名。
String URL = "jdbc:gaussdb://$ip:$port/database?traceInterfaceClass=xxx.xxx.xxx.gaussdbTraceImpl";
com.huawei.gaussdb.jdbc.log.Tracer接口类定义如下。
public interface Tracer { // Retrieves the value of traceId. String getTraceId(); }
import com.huawei.gaussdb.jdbc.log.Tracer; public class gaussdbTraceImpl implements Tracer { private static MDC mdc = new MDC(); private final String TRACE_ID_KEY = "traceId"; public void set(String traceId) { mdc.put(TRACE_ID_KEY, traceId); } public void reset() { mdc.clear(); } @Override public String getTraceId() { return mdc.get(TRACE_ID_KEY); } }
上下文映射示例,用于存放不同请求的生成的traceId。
import java.util.HashMap; public class MDC { static final private ThreadLocal<HashMap<String, String>> threadLocal = new ThreadLocal<>(); public void put(String key, String val) { if (key == null || val == null) { throw new IllegalArgumentException("key or val cannot be null"); } else { if (threadLocal.get() == null) { threadLocal.set(new HashMap<>()); } threadLocal.get().put(key, val); } } public String get(String key) { if (key == null) { throw new IllegalArgumentException("key cannot be null"); } else if (threadLocal.get() == null) { return null; } else { return threadLocal.get().get(key); } } public void clear() { if (threadLocal.get() == null) { return; } else { threadLocal.get().clear(); } } }
业务使用traceId示例,前置条件需要新建table test_trace_id (id int,name varchar(20))。
String traceId = UUID.randomUUID().toString().replaceAll("-", ""); gaussdbTraceImpl gaussdbTrace = new gaussdbTraceImpl(); gaussdbTrace.set(traceId); Connection con = DriverManager.getConnection(url, user, password); pstm = con.prepareStatement("select * from test_trace_id where id = ?"); pstm.setInt(1, 1); pstm.execute(); pstm = con.prepareStatement("insert into test_trace_id values(?,?)"); pstm.setInt(1, 2); pstm.setString(2, "test"); pstm.execute(); gaussdbTrace.reset();
- 使用链路跟踪功能时,应用层链路功能由业务保证。
- 应用必须向JDBC暴露获取traceId的接口,并将该接口实现类配置到JDBC连接串中。
- 同一请求的不同SQL使用的traceId须相同。
- 应用传入的traceId不能超过32字节,否则多余字节将被截断。