项目需要将以下需求进行处理,通过log4j组建输出到log文件进行保存,方便今后运营维护中的分析和问题解决。
项目基本的基本流程包括:
1. 生成若干个独立线程
2. 启动线程进行工作
2.1 根据消息工程生产消息
2.2 将消息转成二进制方式放入输出队列
2.3 启动发送功能,将消息进行加密后发生到服务器端
2.4 等待并读取来自服务器端的消息
需要进行输出的内容主要包括:
1. 发送登陆时间
2. 接收完成登陆时间
3. 发送查询考题时间
4. 接收查询结果的时间
5. 单次登陆操作的花费时间
6. 单次查询考题操作的花费时间
输出到文件output.log
log4j.properties:
[code]
package net.tuolian.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Properties;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.spi.Configurator;
/**
* log4j初始化配置
*
* @author Administrator 1. Property 对象 2.读取配置文件 inputstream 3.
* property.load(is) 4. configure(file); 5.
*
* 错误及解决: 1. log4j.properties文件,需要和代码放在同一级,也就是放在同一个包内
* 2. logger =
* Logger.getLogger(Log4jUtil.class); 否则使用logger对象,报空指针错误
*/
public class Log4jUtil {
private static String fileName = "log4j.properties";
static Logger logger = null;
public Log4jUtil() {
Properties properties = new Properties();
InputStream is = getClass().getResourceAsStream(fileName);
try {
properties.load(is);
PropertyConfigurator.configure(properties);
logger = Logger.getLogger(Log4jUtil.class);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
long startTime = System.currentTimeMillis();
long endTime;
new Log4jUtil();
for (int i = 0; i < 1000; i++) {
System.out.println(" println :" + i);
}
endTime = System.currentTimeMillis();
long takeTime = (endTime - startTime);
logger.info("hello: " + takeTime);
logTime("query time", startTime, endTime);
}
public static void logTime(String logicName, long startTime, long endTime){
logger.info(logicName + "操作使用的时间为" + (endTime - startTime));
}
public void debug(String string) {
// TODO Auto-generated method stub
logger.debug(string);
}
}
[/code]
还有几个小问题:
1. log4j.properties默认是在代码的同一级目录(package)下,比如当前package是net.tuolian.test, 则配置文件放在这个package下就可以被成功加载
2. 根据自己的需要封装方法
比如:封装一个方法来打印业务名称、花费时间
logTime(name, starttime, endTime)
3. 另外log4j的配置文件读取的方法如代码所示:
Properties properties = new Properties();
InputStream is = getClass().getResourceAsStream(fileName);
try {
properties.load(is);
PropertyConfigurator.configure(properties);
logger = Logger.getLogger(Log4jUtil.class);
读取配置文件、设置配置文件,getLogger(类名)
4.将日志输出到数据库,需要对配置文件进行如下设置
输出到数据库
log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test
log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver
log4j.appender.DATABASE.user=root
log4j.appender.DATABASE.password= root
log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n')
log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout
log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
成功与否,笔者还没进行测试
其他方法,还包括输出地格式设定、输出的目标地址设定等等
项目基本的基本流程包括:
1. 生成若干个独立线程
2. 启动线程进行工作
2.1 根据消息工程生产消息
2.2 将消息转成二进制方式放入输出队列
2.3 启动发送功能,将消息进行加密后发生到服务器端
2.4 等待并读取来自服务器端的消息
需要进行输出的内容主要包括:
1. 发送登陆时间
2. 接收完成登陆时间
3. 发送查询考题时间
4. 接收查询结果的时间
5. 单次登陆操作的花费时间
6. 单次查询考题操作的花费时间
输出到文件output.log
log4j.properties:
log4j.rootLogger=DEBUG,stdout
log4j.appender.stdout=org.apache.log4j.RollingFileAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p %c{1}.%M(%L) | %m%n
log4j.appender.stdout.MaxFileSize=30MB
log4j.appender.stdout.MaxBackupIndex=1
log4j.appender.stdout.file=E:\\output.log
/**
*
*/
package net.tuolian.test;
/**
* @author sean
*
* 1. 启动类
* 2. 循环产生100个独立线程
* 3. 启动线程执行任务
*
*/
public class MainTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
for(int i=0; i<500; i++){
UserThread user = new UserThread(i);
new Thread(user).start();
}
}
}
/**
*
*/
package net.tuolian.test;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Date;
import org.apache.log4j.Logger;
/**
* @author sean
* 1. 建立连接
* 2. 填充数据:login, query
* 3. 发生数据
* 4. 接收数据
*
*/
public class UserThread implements Runnable {
Logger logger = null;
Socket socket = null;
private String ip = "192.168.1.2";
// private String ip = "tuolian.gicp.net";
// private String ip = "127.0.0.1";
private int port = 9999;
DataInputStream dis;
DataOutputStream dos;
boolean isRunning = false;
private byte[] outData;
private int id;
private int counter = 0;
Log4jUtil log;
private long startTime;
private long endTime;
public UserThread(int id) {
outData = new byte[512];
this.id = id;
System.out.println(id + " thread is created");
logger = Logger.getLogger(UserThread.class);
log = new Log4jUtil();
}
public void run() {
// TODO Auto-generated method stub
if (!connect()) {
// System.out.println("没有连接");
logger.error("网络没有连接成功");
}
while (isRunning) {
// System.out.println(id + " thread is running");
if (!fillData()) {
// System.out.println("没有添加数据");
logger.error("没有添加数据 ");
}
sendData();
recvData();
if (counter == 1) {
recvData();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 建立网络连接
*
* @return
*/
private boolean connect() {
// TODO Auto-generated method stub
boolean flag = false;
try {
socket = new Socket(ip, port);
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
isRunning = true;
flag = true;
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return flag;
}
/**
* 添加测试数据
* 1. 登陆消息
* 2. 查少询数据库消息
*
*
* @return
*/
private boolean fillData() {
// TODO Auto-generated method stub
boolean flag = false;
outData = null;
counter++;
// System.out.println("counter: " + counter);
//记录操作的开始时间
startTime = System.currentTimeMillis();
if (counter == 1) {
outData = MessageFactory.createMessage(MessageFactory.LOGIN);
} else {
outData = MessageFactory.createMessage(MessageFactory.GETCONTENT);
}
// System.out.println("outdata length: before decrypt " + outData.length);
// 如果内容长度不为空,则设置返回值true
if (outData.length > 0) {
flag = true;
}
return flag;
}
/**
* 发送数据到服务器端 数据从发生队列中读取
*/
private void sendData() {
if (outData.length == 0) {
// System.out.println("发生数据位空,发送出错" + new Date());
log.debug("发生数据位空,发送出错" + new Date());
return;
}
startTime = System.currentTimeMillis();
try {
// 1. tea加密数组 2. 长度数组 3. 发送长度 4. 发生加密后数据 5. flush
// 第二個步骤(长度数组)可以不要
byte[] tempData = Tea.encryptByTea(outData);
// System.out.println(" tempdata after decrypt: " + tempData.length);
dos.write((byte) ((tempData.length & 0xFF)));
// logger.info("temp data length: "
// + ((byte) (tempData.length & 0xFF)));
// System.out.println("temp data length: "
// + ((byte) (tempData.length & 0xFF)));
dos.write((byte) ((tempData.length >> 8 & 0xFF)));
// logger.info("temp data length: "
// + ((byte) (tempData.length >> 8 & 0xFF)));
// System.out.println("temp data length: "
// + ((byte) (tempData.length >> 8 & 0xFF)));
dos.write(tempData);
dos.flush();
// logger.info("outdata length: " + tempData.length);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
outData = null;
}
/**
* 发生数据
*/
private void recvData() {
// TODO Auto-generated method stub
if (dis == null) {
return;
}
try {
if (dis.available() < -1) {
return;
}
// 1. 长度数组2位,读取, 2. 读取加密数据 3. 解密成正常数组 4. 读取包头12个字节
// 5.
// byte[] len = new byte[2];
// dis.read(len);
// //长度2位短整型表示
// int size = Util.BytetoInt2(len,0);
//
// byte[] data = new byte[size];
// dis.read(data);
//
// byte[] finalData = Tea.decryptByTea(data);
//
// //复制包头部分
// byte[] head = new byte[12];
// System.arraycopy(finalData, 0, head, 0, head.length);
//
// char[] tags = new char[2];
// tags[0] = (char) head[0];
// tags[0] = (char) head[1];
//
// //包体长度
// int bodyLen = Util.BytetoInt2(head,2);
//
// //命令头
// int cmdType = Util.BytetoInt2(head,4);
//
// //playerId
// int playerId = Util.BytetoInt4(head, 8);
//
// byte[] body = new byte[bodyLen];
// System.arraycopy(finalData, 12, body, 0, bodyLen);
//
// //进行数据解析和逻辑处理
// parseInputData(cmdType, body , head);
// //通过包头属性,获得包体数据的长度
// //复制包体部分
byte[] datas = new byte[2];
dis.read(datas);
// logger.info("收到消息长度为" + Util.toHexString1(datas));
// short lens=(short) (((datas[0] & 0xFF) << 8) + ((datas[1] & 0xFF)
// << 0));
int len = Util.BytetoInt2(datas, 0);// (short) (((datas[0] & 0xff)
// << 8) + ((datas[1] & 0xff) <<
// 0));
// logger.info("收到消息长度为" + len);
// 读取通信流中的数据
datas = new byte[len];
dis.read(datas);
datas = Tea.decryptByTea(datas);
byte[] headdata = new byte[12];
System.arraycopy(datas, 0, headdata, 0, 12);
// dis.read(headdata);
// headdata=Tea.encryptByTea(headdata);
char[] tags = new char[2];
tags[0] = (char) headdata[0];
tags[1] = (char) headdata[1];
// logger.info("收到body len " + headdata[0]);
int bodyLen = Util.BytetoInt2(headdata, 2);// (short) (((headdata[2]
// & 0xff) << 8) +
// ((headdata[3] & 0xff)
// << 0));
// logger.info("收到body len " + bodyLen);
// headdata[4]
int cmdtype = Util.BytetoInt2(headdata, 4);// (short) (((headdata[4]
// & 0xff) << 8) +
// ((headdata[5] & 0xff)
// << 0));
// headdata[7]
int playerid = Util.BytetoInt4(headdata, 8);
// logger.info("收到player id is " + playerid + " cmd=" + cmdtype);
byte[] bodydata = new byte[bodyLen];
System.arraycopy(datas, 12, bodydata, 0, bodyLen);
// 进行数据解析和逻辑处理
parseInputData(cmdtype, bodydata, headdata);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 解析读取的数据,进行现场处理,打印结果
*
* @param cmdType
* @param body
*/
private void parseInputData(int cmdType, byte[] body, byte[] head) {
// TODO Auto-generated method stub
switch (cmdType) {
case MessageFactory.RE_LOGIN:
int playerId = Util.BytetoInt4(head, 8);
// logger.info("playerId: " + playerId);
endTime = System.currentTimeMillis();
Log4jUtil.logTime("login", startTime, endTime);
// System.out.println("playerId: " + playerId);
break;
case MessageFactory.R_GETTYPE:
// handleGetContent(body);
break;
case MessageFactory.R_GETCONTENT:
handleGetContent(body);
break;
default:
break;
}
}
/**
*
* @param body
*/
private void handleGetContent(byte[] body) {
// TODO Auto-generated method stub
ByteArrayInputStream bis = new ByteArrayInputStream(body);
DataInputStream dis = new DataInputStream(bis);
try {
int id = dis.read();
int style = dis.read();
int sub_style = dis.read();
byte[] data = new byte[2];
dis.read(data);
int len = Util.BytetoInt2(data, 0);
data = new byte[len];
dis.read(data);
String title = new String(data, "utf-8");
// logger.info("question title: " + title);
// System.out.println("question title: " + title);
int slen = dis.read();
// System.out.println(" success in dealing with handleGetContent");
dis.close();
// String[] selects = new String[slen];
// for (int i = 0; i < slen; i++) {
// data = new byte[2];
// dis.read(data);
// int strlen = Util.BytetoInt2(data, 0);
// data = new byte[strlen];
// dis.read(data);
// selects[i] = new String(data, "utf-8");
// dis.close();
// }
// int result = dis.read();
endTime = System.currentTimeMillis();
Log4jUtil.logTime("query", startTime, endTime);
} catch (IOException e) {
// TODO Auto-generated catch block
logger.error("read question error ");
// e.printStackTrace();
}
}
}
package net.tuolian.test;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* 消息工厂
* 1. 产生登陆消息
* 2. 产生数据查询消息
*
* 上述消息都直接写成二进制方式
* 包体+包头
* 放入outData数据队列
*
* @author sean
*
*/
public class MessageFactory {
public static final int LOGIN = 3005;
public static final int GETCONTENT = 2003;
/** ******收到的命令******** */
public static final int RE_LOGIN = 3006;
public static final int R_GETTYPE = 2002;
public static final int R_GETCONTENT = 2004;
private static final String TAG = "tl";
public static byte[] createMessage(int cmdType) {
// TODO Auto-generated method stub
ByteArrayOutputStream writeBos = new ByteArrayOutputStream();
DataOutputStream writeDos = new DataOutputStream(writeBos);
switch (cmdType) {
case LOGIN:
loginWrite(writeDos);
break;
case GETCONTENT:
getContent(writeDos);
break;
default:
break;
}
// 返回加入包头的消息二进制数组
return addMessageHead(writeBos.toByteArray(),cmdType);
// return writeBos.toByteArray();
}
/**
* 添加消息包头,根据具体情况定义包头
* @param body
* @param cmdType
* @return
*/
private static byte[] addMessageHead(byte[] body, int cmdType) {
return data;
// TODO Auto-generated method stub
}
/**
* 编写登陆口命令体
* username
* password
* note:
* log4j记录时间
*
* @param dos
*/
private static void loginWrite(DataOutputStream dos) {
// TODO Auto-generated method stub
int userid = 1000;
String name = "username";
String password = "password";
try {
dos.writeInt(1000);
byte data[] = name.getBytes("UTF-8");
dos.write(data.length & 0xff);
dos.write(data.length >> 8 & 0xff);
dos.write(data);
data = password.getBytes("UTF-8");
dos.write(data.length & 0xff);
dos.write(data.length >> 8 & 0xff);
dos.write(data);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 打印获得考试内容的时间
* @param dos
*/
private static void getContent(DataOutputStream dos) {
// TODO Auto-generated method stub
int examTypeId = 2;
try {
dos.write(examTypeId);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
[code]
package net.tuolian.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Properties;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.spi.Configurator;
/**
* log4j初始化配置
*
* @author Administrator 1. Property 对象 2.读取配置文件 inputstream 3.
* property.load(is) 4. configure(file); 5.
*
* 错误及解决: 1. log4j.properties文件,需要和代码放在同一级,也就是放在同一个包内
* 2. logger =
* Logger.getLogger(Log4jUtil.class); 否则使用logger对象,报空指针错误
*/
public class Log4jUtil {
private static String fileName = "log4j.properties";
static Logger logger = null;
public Log4jUtil() {
Properties properties = new Properties();
InputStream is = getClass().getResourceAsStream(fileName);
try {
properties.load(is);
PropertyConfigurator.configure(properties);
logger = Logger.getLogger(Log4jUtil.class);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
long startTime = System.currentTimeMillis();
long endTime;
new Log4jUtil();
for (int i = 0; i < 1000; i++) {
System.out.println(" println :" + i);
}
endTime = System.currentTimeMillis();
long takeTime = (endTime - startTime);
logger.info("hello: " + takeTime);
logTime("query time", startTime, endTime);
}
public static void logTime(String logicName, long startTime, long endTime){
logger.info(logicName + "操作使用的时间为" + (endTime - startTime));
}
public void debug(String string) {
// TODO Auto-generated method stub
logger.debug(string);
}
}
[/code]
还有几个小问题:
1. log4j.properties默认是在代码的同一级目录(package)下,比如当前package是net.tuolian.test, 则配置文件放在这个package下就可以被成功加载
2. 根据自己的需要封装方法
比如:封装一个方法来打印业务名称、花费时间
logTime(name, starttime, endTime)
3. 另外log4j的配置文件读取的方法如代码所示:
Properties properties = new Properties();
InputStream is = getClass().getResourceAsStream(fileName);
try {
properties.load(is);
PropertyConfigurator.configure(properties);
logger = Logger.getLogger(Log4jUtil.class);
读取配置文件、设置配置文件,getLogger(类名)
4.将日志输出到数据库,需要对配置文件进行如下设置
输出到数据库
log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test
log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver
log4j.appender.DATABASE.user=root
log4j.appender.DATABASE.password= root
log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n')
log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout
log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
成功与否,笔者还没进行测试
其他方法,还包括输出地格式设定、输出的目标地址设定等等