您的位置:首页 > 其它

灰度发布集群服务进行生产环境的日志打印调试

2017-04-01 19:28 375 查看

灰度发布集群服务进行生产环境的日志打印调试

情景模拟:当项目发布之后,某些功能在经过某次确定的操作【1】之后,使另一操作【2】不能正常使用。而当时的源代码由于技术升级,恢复比较困难。在此情景下,需要在线调试。当没有执行操作【1】时,打印操作【2】在执行过程中关键对象的属性值日志信息;当执行了操作【1】时,打印操作【2】在执行过程中关键对象的属性值日志信息。

系统环境: Centos7、Docker1.12.1

应用环境:分布式集群服务,Docker容器化发布,多节点服务应用

说明:

1.在支持打印日志的过程中需要替换Docker容器中的jar包,要求Docker支持docker cp命令;

2.替换的jar和被替换的jar包生成的jdk版本需要一致;

3.在jar包替换之前,最好在容器里先进行备份,然后从容器外拷贝有日志生成功能的相同命名的jar包予以覆盖;

4.由于jar替换之后,容器需要重启,替换的结果才能生效,所以该项目最好是分布式集群服务,支持灰度发布。

问题再现与定位:

由于jdk提供的加密【Cipher 是有状态的,而且是线程不安全的】,即在同一应用中,使用不同的加密方式,彼此之间可能会有影响。在项目上线后,加密模块不定期的会出现加密后的加密串,协作的系统解不出原密码的问题。在此问题下,Cipher对象的变量就成为一个关键的因素,只要在出现问题时,和正常运行时打印出其内的属性值,就可以定位到具体问题,从而进一步解决问题。

在此猜想之下,由于加密模块是自己实现的,那么就可以在获取ciper对象之后打印出其内的属性值,而由于其内的属性几乎都没有提供get方法,所以考虑采用反射机制获取其属性值信息。具体编码如下:

//打印日志
private static Logger loggerError = LoggerFactory.getLogger("com.changan.sso.sdk");

/**
* 通过反射机制打印出对象的属性值信息
*
* @param object
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
private static void getObjectMessage(Object object)
throws IllegalArgumentException, IllegalAccessException {
Class userCla = (Class) object.getClass();
/*
* 得到类中的所有属性集合
*/
Field[] fs = userCla.getDeclaredFields();
for (int i = 0; i < fs.length; i++) {
Field f = fs[i];
f.setAccessible(true); // 设置些属性是可以访问的
Object val = f.get(object); // 得到此属性的值
loggerError.info("name:" + f.getName() + "/t value = " + val);
}
}
/**
* 加密
*
* @param plaintext
* @param key
* @return
*/
public static String encrypt(String plaintext, Key key)
{
try {
// 使用密钥加密
Cipher cipher = Cipher.getInstance("RSA");
loggerError.info("*********************加密cipher信息打印开始******************");
getObjectMessage(cipher);

loggerError.info("*********************加密cipher信息打印结束******************");
cipher.init(Cipher.ENCRYPT_MODE, key);
// 加密后
byte[] result = cipher.doFinal(plaintext.getBytes(UTF8));

// 返回结果
return KeyUtil.encryptBASE64(result);
} catch (Exception e) {
// 打印日志
loggerError.error("加密异常", e);
return null;
}

}


将此代码编写好之后,采用Docker容器中的jdk版本进行编译,必要时构建成jar,并上传至服务器上,通过以下命令将其拷贝到Docker容器内相对应的目录下:

$ docker cp test-1.0.8-SNAPSHOT.jar c33b415ec2de:/apache-tomcat/webapps/test/WEB-INF/lib/


在logback.xml中增加打印给日志信息的文件支持:

<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径 -->
<property name="LOG_HOME" value="/data/core/logs" />

<!-- sso.sdk相关 -->
<appender name="sso.sdk"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<Encoding>UTF-8</Encoding>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>${LOG_HOME}/com.changan.sso.sdk-%d{yyyy-MM-dd}.log
</fileNamePattern>
<!-- 日志最大的历史 30天 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>

<!-- root -->
<logger level="INFO" name="com.changan.sso.sdk">
<appender-ref ref="sso.sdk" />
</logger>
<!-- root -->
<root level="INFO">
<appender-ref ref="console" />
<appender-ref ref="defaultLogFile" />
</root>


添加完毕后,保存并退出容器。执行容器重启命令:

$ docker restart test-web


随后安装执行正确的加密方式调用一次,在按照执行错误的加密方式调用一次,获取的日志信息如下:



从中明显可以得出,两次加密的加密提供商明显不同,问题定位准确,达到检验推测的目的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: