diff --git a/common/pom.xml b/common/pom.xml
index 6cce789f..9e8cb398 100755
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -58,6 +58,11 @@
commons-math3
3.1.1
+
+ cn.hutool
+ hutool-all
+ 4.5.1
+
diff --git a/common/src/main/java/com/alibaba/datax/common/log/EtlJobFileAppender.java b/common/src/main/java/com/alibaba/datax/common/log/EtlJobFileAppender.java
new file mode 100644
index 00000000..1b8225b3
--- /dev/null
+++ b/common/src/main/java/com/alibaba/datax/common/log/EtlJobFileAppender.java
@@ -0,0 +1,73 @@
+package com.alibaba.datax.common.log;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Appender
+ *
+ * @author zhouhongfa@gz-yibo.com
+ * @version 1.0
+ * @since 2019/6/27
+ */
+public class EtlJobFileAppender {
+ private static Logger logger = LoggerFactory.getLogger(EtlJobFileAppender.class);
+
+ // support log for child thread of job handler
+// public static ThreadLocal contextHolder = new ThreadLocal();
+ public static final InheritableThreadLocal contextHolder = new InheritableThreadLocal();
+
+ /**
+ * append log
+ *
+ * @param logFileName
+ * @param appendLog
+ */
+ public static void appendLog(String logFileName, String appendLog) {
+
+ // log file
+ if (logFileName == null || logFileName.trim().length() == 0) {
+ return;
+ }
+ File logFile = new File(logFileName);
+
+ if (!logFile.exists()) {
+ try {
+ logFile.createNewFile();
+ } catch (IOException e) {
+ logger.error(e.getMessage(), e);
+ return;
+ }
+ }
+
+ // log
+ if (appendLog == null) {
+ appendLog = "";
+ }
+ appendLog += "\r\n";
+
+ // append file content
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(logFile, true);
+ fos.write(appendLog.getBytes("utf-8"));
+ fos.flush();
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ } finally {
+ if (fos != null) {
+ try {
+ fos.close();
+ } catch (IOException e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/common/src/main/java/com/alibaba/datax/common/log/EtlJobLogger.java b/common/src/main/java/com/alibaba/datax/common/log/EtlJobLogger.java
new file mode 100644
index 00000000..4e709ca4
--- /dev/null
+++ b/common/src/main/java/com/alibaba/datax/common/log/EtlJobLogger.java
@@ -0,0 +1,88 @@
+package com.alibaba.datax.common.log;
+
+import cn.hutool.core.date.DateUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.helpers.FormattingTuple;
+import org.slf4j.helpers.MessageFormatter;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Date;
+
+/**
+ * datax运行日志工具类,由xxl-job里的com.xxl.job.core.log.XxlJobFileAppender修改而来
+ *
+ * @author zhouhongfa@gz-yibo.com
+ * @version 1.0
+ * @since 2019/6/25
+ */
+public class EtlJobLogger {
+ private static Logger logger = LoggerFactory.getLogger("datax-job logger");
+
+ /**
+ * append log
+ *
+ * @param callInfo
+ * @param appendLog
+ */
+ private static void logDetail(StackTraceElement callInfo, String appendLog) {
+
+
+ /*// "yyyy-MM-dd HH:mm:ss [ClassName]-[MethodName]-[LineNumber]-[ThreadName] log";
+ StackTraceElement[] stackTraceElements = new Throwable().getStackTrace();
+ StackTraceElement callInfo = stackTraceElements[1];*/
+
+ StringBuffer stringBuffer = new StringBuffer();
+ stringBuffer.append(DateUtil.formatDateTime(new Date())).append(" ")
+ .append("[" + callInfo.getClassName() + "#" + callInfo.getMethodName() + "]").append("-")
+ .append("[" + callInfo.getLineNumber() + "]").append("-")
+ .append("[" + Thread.currentThread().getName() + "]").append(" ")
+ .append(appendLog != null ? appendLog : "");
+ String formatAppendLog = stringBuffer.toString();
+
+ // appendlog
+ String logFileName = EtlJobFileAppender.contextHolder.get();
+ if (logFileName != null && logFileName.trim().length() > 0) {
+ EtlJobFileAppender.appendLog(logFileName, formatAppendLog);
+ } else {
+ logger.info(">>>>>>>>>>> {}", formatAppendLog);
+ }
+ }
+
+ /**
+ * append log with pattern
+ *
+ * @param appendLogPattern like "aaa {} bbb {} ccc"
+ * @param appendLogArguments like "111, true"
+ */
+ public static void log(String appendLogPattern, Object... appendLogArguments) {
+
+ FormattingTuple ft = MessageFormatter.arrayFormat(appendLogPattern, appendLogArguments);
+ String appendLog = ft.getMessage();
+
+ /*appendLog = appendLogPattern;
+ if (appendLogArguments!=null && appendLogArguments.length>0) {
+ appendLog = MessageFormat.format(appendLogPattern, appendLogArguments);
+ }*/
+
+ StackTraceElement callInfo = new Throwable().getStackTrace()[1];
+ logDetail(callInfo, appendLog);
+ }
+
+ /**
+ * append exception stack
+ *
+ * @param e
+ */
+ public static void log(Throwable e) {
+
+ StringWriter stringWriter = new StringWriter();
+ e.printStackTrace(new PrintWriter(stringWriter));
+ String appendLog = stringWriter.toString();
+
+ StackTraceElement callInfo = new Throwable().getStackTrace()[1];
+ logDetail(callInfo, appendLog);
+ }
+
+}