Browse Source
* Use MDC to collect task instance log * Use MDCAutoClosableContext to remove the MDC key3.2.0-release
Wenjun Ruan
2 years ago
committed by
GitHub
59 changed files with 506 additions and 1084 deletions
@ -0,0 +1,77 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!-- |
||||||
|
~ 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. |
||||||
|
--> |
||||||
|
|
||||||
|
<configuration scan="true" scanPeriod="120 seconds"> |
||||||
|
<property name="log.base" value="logs"/> |
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> |
||||||
|
<encoder> |
||||||
|
<pattern> |
||||||
|
[%level] %date{yyyy-MM-dd HH:mm:ss.SSS Z} %logger{96}:[%line] - [WorkflowInstance-%X{workflowInstanceId:-0}][TaskInstance-%X{taskInstanceId:-0}] - %msg%n |
||||||
|
</pattern> |
||||||
|
<charset>UTF-8</charset> |
||||||
|
</encoder> |
||||||
|
</appender> |
||||||
|
|
||||||
|
<conversionRule conversionWord="message" |
||||||
|
converterClass="org.apache.dolphinscheduler.common.log.SensitiveDataConverter"/> |
||||||
|
<appender name="TASKLOGFILE" class="ch.qos.logback.classic.sift.SiftingAppender"> |
||||||
|
<filter class="org.apache.dolphinscheduler.plugin.task.api.log.TaskLogFilter"/> |
||||||
|
<Discriminator class="org.apache.dolphinscheduler.plugin.task.api.log.TaskLogDiscriminator"> |
||||||
|
<key>taskInstanceLogFullPath</key> |
||||||
|
<logBase>${log.base}</logBase> |
||||||
|
</Discriminator> |
||||||
|
<sift> |
||||||
|
<appender name="FILE-${taskInstanceLogFullPath}" class="ch.qos.logback.core.FileAppender"> |
||||||
|
<file>${taskInstanceLogFullPath}</file> |
||||||
|
<encoder> |
||||||
|
<pattern> |
||||||
|
[%level] %date{yyyy-MM-dd HH:mm:ss.SSS Z} - %message%n |
||||||
|
</pattern> |
||||||
|
<charset>UTF-8</charset> |
||||||
|
</encoder> |
||||||
|
<append>true</append> |
||||||
|
</appender> |
||||||
|
</sift> |
||||||
|
</appender> |
||||||
|
<appender name="MASTERLOGFILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
||||||
|
<file>${log.base}/dolphinscheduler-master.log</file> |
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> |
||||||
|
<fileNamePattern>${log.base}/dolphinscheduler-master.%d{yyyy-MM-dd_HH}.%i.log</fileNamePattern> |
||||||
|
<maxHistory>168</maxHistory> |
||||||
|
<maxFileSize>200MB</maxFileSize> |
||||||
|
<totalSizeCap>50GB</totalSizeCap> |
||||||
|
<cleanHistoryOnStart>true</cleanHistoryOnStart> |
||||||
|
</rollingPolicy> |
||||||
|
<encoder> |
||||||
|
<pattern> |
||||||
|
[%level] %date{yyyy-MM-dd HH:mm:ss.SSS Z} %logger{96}:[%line] - [WorkflowInstance-%X{workflowInstanceId:-0}][TaskInstance-%X{taskInstanceId:-0}] - %msg%n |
||||||
|
</pattern> |
||||||
|
<charset>UTF-8</charset> |
||||||
|
</encoder> |
||||||
|
</appender> |
||||||
|
|
||||||
|
<root level="INFO"> |
||||||
|
<if condition="${DOCKER:-false}"> |
||||||
|
<then> |
||||||
|
<appender-ref ref="STDOUT"/> |
||||||
|
</then> |
||||||
|
</if> |
||||||
|
<appender-ref ref="TASKLOGFILE"/> |
||||||
|
<appender-ref ref="MASTERLOGFILE"/> |
||||||
|
</root> |
||||||
|
</configuration> |
@ -1,85 +0,0 @@ |
|||||||
/* |
|
||||||
* 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.dolphinscheduler.service.utils; |
|
||||||
|
|
||||||
import org.apache.dolphinscheduler.common.constants.Constants; |
|
||||||
import org.apache.dolphinscheduler.common.constants.DateConstants; |
|
||||||
import org.apache.dolphinscheduler.common.utils.DateUtils; |
|
||||||
import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; |
|
||||||
import org.apache.dolphinscheduler.plugin.task.api.log.TaskLogDiscriminator; |
|
||||||
|
|
||||||
import java.nio.file.Path; |
|
||||||
import java.nio.file.Paths; |
|
||||||
import java.util.Date; |
|
||||||
import java.util.Optional; |
|
||||||
|
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
import ch.qos.logback.classic.sift.SiftingAppender; |
|
||||||
import ch.qos.logback.classic.spi.ILoggingEvent; |
|
||||||
import ch.qos.logback.core.spi.AppenderAttachable; |
|
||||||
|
|
||||||
public class LogUtils { |
|
||||||
|
|
||||||
public static final String LOG_TAILFIX = ".log"; |
|
||||||
|
|
||||||
private LogUtils() throws IllegalStateException { |
|
||||||
throw new IllegalStateException("Utility class"); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* get task log path |
|
||||||
*/ |
|
||||||
public static String getTaskLogPath(Date firstSubmitTime, Long processDefineCode, int processDefineVersion, |
|
||||||
int processInstanceId, int taskInstanceId) { |
|
||||||
// format /logs/YYYYMMDD/defintion-code_defintion_version-processInstanceId-taskInstanceId.log
|
|
||||||
final String taskLogFileName = new StringBuilder(String.valueOf(processDefineCode)) |
|
||||||
.append(Constants.UNDERLINE) |
|
||||||
.append(processDefineVersion) |
|
||||||
.append(Constants.SUBTRACT_CHAR) |
|
||||||
.append(processInstanceId) |
|
||||||
.append(Constants.SUBTRACT_CHAR) |
|
||||||
.append(taskInstanceId) |
|
||||||
.append(LOG_TAILFIX) |
|
||||||
.toString(); |
|
||||||
// Optional.map will be skipped if null
|
|
||||||
return Optional.of(LoggerFactory.getILoggerFactory()) |
|
||||||
.map(e -> (AppenderAttachable<ILoggingEvent>) (e.getLogger("ROOT"))) |
|
||||||
.map(e -> (SiftingAppender) (e.getAppender("TASKLOGFILE"))) |
|
||||||
.map(e -> ((TaskLogDiscriminator) (e.getDiscriminator()))) |
|
||||||
.map(TaskLogDiscriminator::getLogBase) |
|
||||||
.map(e -> Paths.get(e) |
|
||||||
.toAbsolutePath() |
|
||||||
.resolve(DateUtils.format(firstSubmitTime, DateConstants.YYYYMMDD, null)) |
|
||||||
.resolve(taskLogFileName)) |
|
||||||
.map(Path::toString) |
|
||||||
.orElse(""); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* get task log path by TaskExecutionContext |
|
||||||
*/ |
|
||||||
public static String getTaskLogPath(TaskExecutionContext taskExecutionContext) { |
|
||||||
return getTaskLogPath(DateUtils.timeStampToDate(taskExecutionContext.getFirstSubmitTime()), |
|
||||||
taskExecutionContext.getProcessDefineCode(), |
|
||||||
taskExecutionContext.getProcessDefineVersion(), |
|
||||||
taskExecutionContext.getProcessInstanceId(), |
|
||||||
taskExecutionContext.getTaskInstanceId()); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,119 +0,0 @@ |
|||||||
/* |
|
||||||
* 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.dolphinscheduler.service.utils; |
|
||||||
|
|
||||||
import org.apache.dolphinscheduler.common.constants.Constants; |
|
||||||
import org.apache.dolphinscheduler.common.constants.DateConstants; |
|
||||||
import org.apache.dolphinscheduler.common.utils.DateUtils; |
|
||||||
import org.apache.dolphinscheduler.plugin.task.api.TaskConstants; |
|
||||||
|
|
||||||
import java.io.BufferedReader; |
|
||||||
import java.io.FileInputStream; |
|
||||||
import java.io.IOException; |
|
||||||
import java.io.InputStreamReader; |
|
||||||
import java.util.Date; |
|
||||||
|
|
||||||
import lombok.experimental.UtilityClass; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
|
|
||||||
import org.slf4j.MDC; |
|
||||||
|
|
||||||
/** |
|
||||||
* Please use {@link org.apache.dolphinscheduler.plugin.task.api.utils.LogUtils}. |
|
||||||
*/ |
|
||||||
@Deprecated |
|
||||||
@UtilityClass |
|
||||||
@Slf4j |
|
||||||
public class LoggerUtils { |
|
||||||
|
|
||||||
public static String buildTaskId(Date firstSubmitTime, |
|
||||||
Long processDefineCode, |
|
||||||
int processDefineVersion, |
|
||||||
int processInstId, |
|
||||||
int taskId) { |
|
||||||
// like TaskAppId=TASK-20211107-798_1-4084-15210
|
|
||||||
String firstSubmitTimeStr = DateUtils.format(firstSubmitTime, DateConstants.YYYYMMDD, null); |
|
||||||
return String.format("%s=%s-%s-%s_%s-%s-%s", |
|
||||||
TaskConstants.TASK_APPID_LOG_FORMAT, TaskConstants.TASK_LOGGER_INFO_PREFIX, firstSubmitTimeStr, |
|
||||||
processDefineCode, processDefineVersion, processInstId, taskId); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* read whole file content |
|
||||||
* |
|
||||||
* @param filePath file path |
|
||||||
* @return whole file content |
|
||||||
*/ |
|
||||||
public static String readWholeFileContent(String filePath) { |
|
||||||
String line; |
|
||||||
StringBuilder sb = new StringBuilder(); |
|
||||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)))) { |
|
||||||
while ((line = br.readLine()) != null) { |
|
||||||
sb.append(line + "\r\n"); |
|
||||||
} |
|
||||||
return sb.toString(); |
|
||||||
} catch (IOException e) { |
|
||||||
log.error("read file error", e); |
|
||||||
} |
|
||||||
return ""; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Please use {@link org.apache.dolphinscheduler.plugin.task.api.utils.LogUtils} |
|
||||||
*/ |
|
||||||
public static void setWorkflowAndTaskInstanceIDMDC(Integer workflowInstanceId, Integer taskInstanceId) { |
|
||||||
setWorkflowInstanceIdMDC(workflowInstanceId); |
|
||||||
setTaskInstanceIdMDC(taskInstanceId); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Please use {@link org.apache.dolphinscheduler.plugin.task.api.utils.LogUtils} |
|
||||||
*/ |
|
||||||
public static void setWorkflowInstanceIdMDC(Integer workflowInstanceId) { |
|
||||||
MDC.put(Constants.WORKFLOW_INSTANCE_ID_MDC_KEY, String.valueOf(workflowInstanceId)); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Please use {@link org.apache.dolphinscheduler.plugin.task.api.utils.LogUtils} |
|
||||||
*/ |
|
||||||
public static void setTaskInstanceIdMDC(Integer taskInstanceId) { |
|
||||||
MDC.put(Constants.TASK_INSTANCE_ID_MDC_KEY, String.valueOf(taskInstanceId)); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Please use {@link org.apache.dolphinscheduler.plugin.task.api.utils.LogUtils} |
|
||||||
*/ |
|
||||||
public static void removeWorkflowAndTaskInstanceIdMDC() { |
|
||||||
removeWorkflowInstanceIdMDC(); |
|
||||||
removeTaskInstanceIdMDC(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Please use {@link org.apache.dolphinscheduler.plugin.task.api.utils.LogUtils} |
|
||||||
*/ |
|
||||||
public static void removeWorkflowInstanceIdMDC() { |
|
||||||
MDC.remove(Constants.WORKFLOW_INSTANCE_ID_MDC_KEY); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Please use {@link org.apache.dolphinscheduler.plugin.task.api.utils.LogUtils} |
|
||||||
*/ |
|
||||||
public static void removeTaskInstanceIdMDC() { |
|
||||||
MDC.remove(Constants.TASK_INSTANCE_ID_MDC_KEY); |
|
||||||
} |
|
||||||
} |
|
@ -1,151 +0,0 @@ |
|||||||
/* |
|
||||||
* 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.dolphinscheduler.service.log; |
|
||||||
|
|
||||||
import org.apache.dolphinscheduler.common.utils.JSONUtils; |
|
||||||
import org.apache.dolphinscheduler.common.utils.NetUtils; |
|
||||||
import org.apache.dolphinscheduler.remote.NettyRemotingClient; |
|
||||||
import org.apache.dolphinscheduler.remote.command.Command; |
|
||||||
import org.apache.dolphinscheduler.remote.command.log.GetLogBytesResponseCommand; |
|
||||||
import org.apache.dolphinscheduler.remote.command.log.RollViewLogResponseCommand; |
|
||||||
import org.apache.dolphinscheduler.remote.command.log.ViewLogResponseCommand; |
|
||||||
import org.apache.dolphinscheduler.remote.factory.NettyRemotingClientFactory; |
|
||||||
import org.apache.dolphinscheduler.remote.utils.Host; |
|
||||||
import org.apache.dolphinscheduler.service.utils.LoggerUtils; |
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets; |
|
||||||
|
|
||||||
import org.junit.jupiter.api.Assertions; |
|
||||||
import org.junit.jupiter.api.Test; |
|
||||||
import org.junit.jupiter.api.extension.ExtendWith; |
|
||||||
import org.mockito.MockedStatic; |
|
||||||
import org.mockito.Mockito; |
|
||||||
import org.mockito.junit.jupiter.MockitoExtension; |
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class) |
|
||||||
public class LogClientTest { |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testViewLogFromLocal() { |
|
||||||
String localMachine = "LOCAL_MACHINE"; |
|
||||||
int port = 1234; |
|
||||||
String path = "/tmp/log"; |
|
||||||
|
|
||||||
try ( |
|
||||||
MockedStatic<NetUtils> mockedNetUtils = Mockito.mockStatic(NetUtils.class); |
|
||||||
MockedStatic<LoggerUtils> mockedLoggerUtils = Mockito.mockStatic(LoggerUtils.class)) { |
|
||||||
mockedNetUtils.when(NetUtils::getHost) |
|
||||||
.thenReturn(localMachine); |
|
||||||
mockedLoggerUtils.when(() -> LoggerUtils.readWholeFileContent(Mockito.anyString())) |
|
||||||
.thenReturn("application_xx_11"); |
|
||||||
LogClient logClient = new LogClient(); |
|
||||||
String log = logClient.viewLog(localMachine, port, path); |
|
||||||
Assertions.assertNotNull(log); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testViewLogFromRemote() throws Exception { |
|
||||||
String localMachine = "127.0.0.1"; |
|
||||||
int port = 1234; |
|
||||||
String path = "/tmp/log"; |
|
||||||
|
|
||||||
try (MockedStatic<NetUtils> mockedNetUtils = Mockito.mockStatic(NetUtils.class)) { |
|
||||||
mockedNetUtils.when(NetUtils::getHost) |
|
||||||
.thenReturn(localMachine + "1"); |
|
||||||
LogClient logClient = new LogClient(); |
|
||||||
String log = logClient.viewLog(localMachine, port, path); |
|
||||||
Assertions.assertNotNull(log); |
|
||||||
} |
|
||||||
|
|
||||||
Command command = new Command(); |
|
||||||
command.setBody(JSONUtils.toJsonString(new ViewLogResponseCommand("")).getBytes(StandardCharsets.UTF_8)); |
|
||||||
LogClient logClient = new LogClient(); |
|
||||||
String log = logClient.viewLog(localMachine, port, path); |
|
||||||
Assertions.assertNotNull(log); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testClose() { |
|
||||||
try ( |
|
||||||
MockedStatic<NettyRemotingClientFactory> mockedNettyRemotingClientFactory = |
|
||||||
Mockito.mockStatic(NettyRemotingClientFactory.class)) { |
|
||||||
NettyRemotingClient remotingClient = Mockito.mock(NettyRemotingClient.class); |
|
||||||
mockedNettyRemotingClientFactory.when(NettyRemotingClientFactory::buildNettyRemotingClient) |
|
||||||
.thenReturn(remotingClient); |
|
||||||
LogClient logClient = new LogClient(); |
|
||||||
logClient.close(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testRollViewLog() throws Exception { |
|
||||||
try ( |
|
||||||
MockedStatic<NettyRemotingClientFactory> mockedNettyRemotingClientFactory = |
|
||||||
Mockito.mockStatic(NettyRemotingClientFactory.class)) { |
|
||||||
NettyRemotingClient remotingClient = Mockito.mock(NettyRemotingClient.class); |
|
||||||
mockedNettyRemotingClientFactory.when(NettyRemotingClientFactory::buildNettyRemotingClient) |
|
||||||
.thenReturn(remotingClient); |
|
||||||
Command command = new Command(); |
|
||||||
command.setBody(JSONUtils.toJsonByteArray(new RollViewLogResponseCommand("success"))); |
|
||||||
Mockito.when( |
|
||||||
remotingClient.sendSync(Mockito.any(Host.class), Mockito.any(Command.class), Mockito.anyLong())) |
|
||||||
.thenReturn(command); |
|
||||||
|
|
||||||
LogClient logClient = new LogClient(); |
|
||||||
String msg = logClient.rollViewLog("localhost", 1234, "/tmp/log", 0, 10); |
|
||||||
Assertions.assertNotNull(msg); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testGetLogBytes() throws Exception { |
|
||||||
try ( |
|
||||||
MockedStatic<NettyRemotingClientFactory> mockedNettyRemotingClientFactory = |
|
||||||
Mockito.mockStatic(NettyRemotingClientFactory.class)) { |
|
||||||
NettyRemotingClient remotingClient = Mockito.mock(NettyRemotingClient.class); |
|
||||||
mockedNettyRemotingClientFactory.when(NettyRemotingClientFactory::buildNettyRemotingClient) |
|
||||||
.thenReturn(remotingClient); |
|
||||||
Command command = new Command(); |
|
||||||
command.setBody( |
|
||||||
JSONUtils.toJsonByteArray(new GetLogBytesResponseCommand("log".getBytes(StandardCharsets.UTF_8)))); |
|
||||||
Mockito.when( |
|
||||||
remotingClient.sendSync(Mockito.any(Host.class), Mockito.any(Command.class), Mockito.anyLong())) |
|
||||||
.thenReturn(command); |
|
||||||
|
|
||||||
LogClient logClient = new LogClient(); |
|
||||||
byte[] logBytes = logClient.getLogBytes("localhost", 1234, "/tmp/log"); |
|
||||||
Assertions.assertNotNull(logBytes); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testRemoveTaskLog() { |
|
||||||
|
|
||||||
try ( |
|
||||||
MockedStatic<NettyRemotingClientFactory> mockedNettyRemotingClientFactory = |
|
||||||
Mockito.mockStatic(NettyRemotingClientFactory.class)) { |
|
||||||
NettyRemotingClient remotingClient = Mockito.mock(NettyRemotingClient.class); |
|
||||||
mockedNettyRemotingClientFactory.when(NettyRemotingClientFactory::buildNettyRemotingClient) |
|
||||||
.thenReturn(remotingClient); |
|
||||||
|
|
||||||
LogClient logClient = new LogClient(); |
|
||||||
Assertions.assertDoesNotThrow(() -> logClient.removeTaskLog(Host.of("localhost:1234"), "/log/path")); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,108 +0,0 @@ |
|||||||
/* |
|
||||||
* 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.dolphinscheduler.service.log; |
|
||||||
|
|
||||||
import org.apache.dolphinscheduler.plugin.task.api.TaskConstants; |
|
||||||
import org.apache.dolphinscheduler.plugin.task.api.log.TaskLogDiscriminator; |
|
||||||
|
|
||||||
import org.junit.jupiter.api.Assertions; |
|
||||||
import org.junit.jupiter.api.BeforeEach; |
|
||||||
import org.junit.jupiter.api.Test; |
|
||||||
|
|
||||||
import ch.qos.logback.classic.Level; |
|
||||||
import ch.qos.logback.classic.spi.LoggingEvent; |
|
||||||
|
|
||||||
public class TaskLogDiscriminatorTest { |
|
||||||
|
|
||||||
/** |
|
||||||
* log base |
|
||||||
*/ |
|
||||||
private String logBase = "logs"; |
|
||||||
|
|
||||||
TaskLogDiscriminator taskLogDiscriminator; |
|
||||||
|
|
||||||
@BeforeEach |
|
||||||
public void before() { |
|
||||||
taskLogDiscriminator = new TaskLogDiscriminator(); |
|
||||||
taskLogDiscriminator.setLogBase("logs"); |
|
||||||
taskLogDiscriminator.setKey("123"); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getDiscriminatingValue() { |
|
||||||
String result = taskLogDiscriminator.getDiscriminatingValue(new LoggingEvent() { |
|
||||||
|
|
||||||
@Override |
|
||||||
public String getThreadName() { |
|
||||||
return "taskAppId=TASK-20220105-101-1-1001"; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Level getLevel() { |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String getMessage() { |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Object[] getArgumentArray() { |
|
||||||
return new Object[0]; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String getFormattedMessage() { |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String getLoggerName() { |
|
||||||
return TaskConstants.TASK_LOG_LOGGER_NAME; |
|
||||||
} |
|
||||||
}); |
|
||||||
Assertions.assertEquals("20220105/101-1-1001", result); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void start() { |
|
||||||
taskLogDiscriminator.start(); |
|
||||||
Assertions.assertEquals(true, taskLogDiscriminator.isStarted()); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getKey() { |
|
||||||
Assertions.assertEquals("123", taskLogDiscriminator.getKey()); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void setKey() { |
|
||||||
|
|
||||||
taskLogDiscriminator.setKey("123"); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void getLogBase() { |
|
||||||
Assertions.assertEquals("logs", taskLogDiscriminator.getLogBase()); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void setLogBase() { |
|
||||||
taskLogDiscriminator.setLogBase("logs"); |
|
||||||
} |
|
||||||
} |
|
@ -1,71 +0,0 @@ |
|||||||
/* |
|
||||||
* 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.dolphinscheduler.service.log; |
|
||||||
|
|
||||||
import org.apache.dolphinscheduler.plugin.task.api.TaskConstants; |
|
||||||
import org.apache.dolphinscheduler.plugin.task.api.log.TaskLogFilter; |
|
||||||
|
|
||||||
import org.junit.jupiter.api.Assertions; |
|
||||||
import org.junit.jupiter.api.Test; |
|
||||||
|
|
||||||
import ch.qos.logback.classic.Level; |
|
||||||
import ch.qos.logback.classic.spi.LoggingEvent; |
|
||||||
import ch.qos.logback.core.spi.FilterReply; |
|
||||||
|
|
||||||
public class TaskLogFilterTest { |
|
||||||
|
|
||||||
@Test |
|
||||||
public void decide() { |
|
||||||
TaskLogFilter taskLogFilter = new TaskLogFilter(); |
|
||||||
|
|
||||||
FilterReply filterReply = taskLogFilter.decide(new LoggingEvent() { |
|
||||||
|
|
||||||
@Override |
|
||||||
public String getThreadName() { |
|
||||||
return TaskConstants.TASK_APPID_LOG_FORMAT; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Level getLevel() { |
|
||||||
return Level.INFO; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String getMessage() { |
|
||||||
return "raw script : echo 222"; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Object[] getArgumentArray() { |
|
||||||
return new Object[0]; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String getFormattedMessage() { |
|
||||||
return "raw script : echo 222"; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String getLoggerName() { |
|
||||||
return TaskConstants.TASK_LOG_LOGGER_NAME; |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
Assertions.assertEquals(FilterReply.ACCEPT, filterReply); |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
@ -1,73 +0,0 @@ |
|||||||
/* |
|
||||||
* 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.dolphinscheduler.service.utils; |
|
||||||
|
|
||||||
import org.apache.dolphinscheduler.common.constants.DateConstants; |
|
||||||
import org.apache.dolphinscheduler.common.utils.DateUtils; |
|
||||||
import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; |
|
||||||
import org.apache.dolphinscheduler.plugin.task.api.log.TaskLogDiscriminator; |
|
||||||
|
|
||||||
import java.nio.file.Path; |
|
||||||
import java.nio.file.Paths; |
|
||||||
import java.util.Date; |
|
||||||
|
|
||||||
import org.junit.jupiter.api.Assertions; |
|
||||||
import org.junit.jupiter.api.Test; |
|
||||||
import org.junit.jupiter.api.extension.ExtendWith; |
|
||||||
import org.mockito.Mockito; |
|
||||||
import org.mockito.junit.jupiter.MockitoExtension; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
import ch.qos.logback.classic.Logger; |
|
||||||
import ch.qos.logback.classic.sift.SiftingAppender; |
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class) |
|
||||||
public class LogUtilsTest { |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testGetTaskLogPath() { |
|
||||||
Date firstSubmitTime = new Date(); |
|
||||||
TaskExecutionContext taskExecutionContext = new TaskExecutionContext(); |
|
||||||
taskExecutionContext.setProcessInstanceId(100); |
|
||||||
taskExecutionContext.setTaskInstanceId(1000); |
|
||||||
taskExecutionContext.setProcessDefineCode(1L); |
|
||||||
taskExecutionContext.setProcessDefineVersion(1); |
|
||||||
taskExecutionContext.setFirstSubmitTime(firstSubmitTime.getTime()); |
|
||||||
|
|
||||||
Logger rootLogger = (Logger) LoggerFactory.getILoggerFactory().getLogger("ROOT"); |
|
||||||
Assertions.assertNotNull(rootLogger); |
|
||||||
|
|
||||||
SiftingAppender appender = Mockito.mock(SiftingAppender.class); |
|
||||||
// it's a trick to mock logger.getAppend("TASKLOGFILE")
|
|
||||||
Mockito.when(appender.getName()).thenReturn("TASKLOGFILE"); |
|
||||||
rootLogger.addAppender(appender); |
|
||||||
|
|
||||||
Path logBase = Paths.get("path").resolve("to").resolve("test"); |
|
||||||
|
|
||||||
TaskLogDiscriminator taskLogDiscriminator = Mockito.mock(TaskLogDiscriminator.class); |
|
||||||
Mockito.when(taskLogDiscriminator.getLogBase()).thenReturn(logBase.toString()); |
|
||||||
Mockito.when(appender.getDiscriminator()).thenReturn(taskLogDiscriminator); |
|
||||||
|
|
||||||
Path logPath = Paths.get(".").toAbsolutePath().getParent() |
|
||||||
.resolve(logBase) |
|
||||||
.resolve(DateUtils.format(firstSubmitTime, DateConstants.YYYYMMDD, null)) |
|
||||||
.resolve("1_1-100-1000.log"); |
|
||||||
Assertions.assertEquals(logPath.toString(), LogUtils.getTaskLogPath(taskExecutionContext)); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,78 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!-- |
||||||
|
~ 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. |
||||||
|
--> |
||||||
|
|
||||||
|
<configuration scan="true" scanPeriod="120 seconds"> |
||||||
|
<property name="log.base" value="logs"/> |
||||||
|
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> |
||||||
|
<encoder> |
||||||
|
<pattern> |
||||||
|
[%level] %date{yyyy-MM-dd HH:mm:ss.SSS Z} %logger{96}:[%line] - [WorkflowInstance-%X{workflowInstanceId:-0}][TaskInstance-%X{taskInstanceId:-0}] - %msg%n |
||||||
|
</pattern> |
||||||
|
<charset>UTF-8</charset> |
||||||
|
</encoder> |
||||||
|
</appender> |
||||||
|
|
||||||
|
<conversionRule conversionWord="message" |
||||||
|
converterClass="org.apache.dolphinscheduler.common.log.SensitiveDataConverter"/> |
||||||
|
<appender name="TASKLOGFILE" class="ch.qos.logback.classic.sift.SiftingAppender"> |
||||||
|
<filter class="org.apache.dolphinscheduler.plugin.task.api.log.TaskLogFilter"/> |
||||||
|
<Discriminator class="org.apache.dolphinscheduler.plugin.task.api.log.TaskLogDiscriminator"> |
||||||
|
<key>taskInstanceLogFullPath</key> |
||||||
|
<logBase>${log.base}</logBase> |
||||||
|
</Discriminator> |
||||||
|
<sift> |
||||||
|
<appender name="FILE-${taskInstanceLogFullPath}" class="ch.qos.logback.core.FileAppender"> |
||||||
|
<file>${taskInstanceLogFullPath}</file> |
||||||
|
<encoder> |
||||||
|
<pattern> |
||||||
|
[%level] %date{yyyy-MM-dd HH:mm:ss.SSS Z} - %message%n |
||||||
|
</pattern> |
||||||
|
<charset>UTF-8</charset> |
||||||
|
</encoder> |
||||||
|
<append>true</append> |
||||||
|
</appender> |
||||||
|
</sift> |
||||||
|
</appender> |
||||||
|
<appender name="WORKERLOGFILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
||||||
|
<file>${log.base}/dolphinscheduler-worker.log</file> |
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> |
||||||
|
<fileNamePattern>${log.base}/dolphinscheduler-worker.%d{yyyy-MM-dd_HH}.%i.log</fileNamePattern> |
||||||
|
<maxHistory>168</maxHistory> |
||||||
|
<maxFileSize>200MB</maxFileSize> |
||||||
|
<totalSizeCap>50GB</totalSizeCap> |
||||||
|
<cleanHistoryOnStart>true</cleanHistoryOnStart> |
||||||
|
</rollingPolicy> |
||||||
|
<encoder> |
||||||
|
<pattern> |
||||||
|
[%level] %date{yyyy-MM-dd HH:mm:ss.SSS Z} %logger{96}:[%line] - [WorkflowInstance-%X{workflowInstanceId:-0}][TaskInstance-%X{taskInstanceId:-0}] - %msg%n |
||||||
|
</pattern> |
||||||
|
<charset>UTF-8</charset> |
||||||
|
</encoder> |
||||||
|
</appender> |
||||||
|
|
||||||
|
<root level="INFO"> |
||||||
|
<if condition="${DOCKER:-false}"> |
||||||
|
<then> |
||||||
|
<appender-ref ref="STDOUT"/> |
||||||
|
</then> |
||||||
|
</if> |
||||||
|
<appender-ref ref="TASKLOGFILE"/> |
||||||
|
<appender-ref ref="WORKERLOGFILE"/> |
||||||
|
</root> |
||||||
|
</configuration> |
Loading…
Reference in new issue