Browse Source

[Feature-5822][api] Add audit log (#6322)

* rebase

* update audit log type name

* fix the quoted property error

* fix bug

* update audit global switch default value

* fix wrong ddl comment

* fix wrong code style

* update audit log search sql

* add licenses

* add unit test

* fix wrong code style

* fix bugs

* fix wrong code style

* add test case

* add test case

* add license

* Add unit test in pom.xml

* resolve code smell problem

* mysql and postgresql ddl update

* update audit log path and audit page query

* update audit configuration

* update audit log schema, add resource type and resource id

* update audit query and list page

* resolve audit log front page bugs and log query error

* update audit configuration

* resolve wrong configuration

* update AuditLogControllerTest

* update application.yaml

* resolve code smell

* update standalone configuration

* resolve bugs

Co-authored-by: yc322 <1393242780@qq.com>
3.0.0/version-upgrade
yc322 2 years ago committed by GitHub
parent
commit
fb9f4a1339
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 94
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/audit/AuditMessage.java
  2. 93
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/audit/AuditPublishService.java
  3. 28
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/audit/AuditSubscriber.java
  4. 42
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/audit/AuditSubscriberImpl.java
  5. 37
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/configuration/AuditConfiguration.java
  6. 98
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/AuditLogController.java
  7. 76
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/dto/AuditDto.java
  8. 3
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
  9. 57
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/AuditService.java
  10. 137
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/AuditServiceImpl.java
  11. 3
      dolphinscheduler-api/src/main/resources/application.yaml
  12. 3
      dolphinscheduler-api/src/main/resources/i18n/messages.properties
  13. 4
      dolphinscheduler-api/src/main/resources/i18n/messages_en_US.properties
  14. 4
      dolphinscheduler-api/src/main/resources/i18n/messages_zh_CN.properties
  15. 49
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/audit/AuditSubscriberTest.java
  16. 40
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/configuration/AuditConfigurationTest.java
  17. 61
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/AuditLogControllerTest.java
  18. 91
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/AuditServiceTest.java
  19. 3
      dolphinscheduler-api/src/test/resources/application.yaml
  20. 62
      dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/AuditOperationType.java
  21. 60
      dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/AuditResourceType.java
  22. 116
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/AuditLog.java
  23. 42
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/AuditLogMapper.java
  24. 64
      dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/AuditLogMapper.xml
  25. 15
      dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql
  26. 14
      dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql
  27. 14
      dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql
  28. 14
      dolphinscheduler-dao/src/main/resources/sql/upgrade/2.0.0_schema/mysql/dolphinscheduler_ddl.sql
  29. 10
      dolphinscheduler-dao/src/main/resources/sql/upgrade/2.0.0_schema/postgresql/dolphinscheduler_ddl.sql
  30. 70
      dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/AuditLogMapperTest.java
  31. 3
      dolphinscheduler-standalone-server/src/main/resources/application.yaml
  32. 127
      dolphinscheduler-ui/src/js/conf/home/pages/monitor/pages/_source/conditions/audit/auditLog.vue
  33. 60
      dolphinscheduler-ui/src/js/conf/home/pages/monitor/pages/_source/conditions/audit/common.js
  34. 24
      dolphinscheduler-ui/src/js/conf/home/pages/monitor/pages/_source/conditions/index.vue
  35. 72
      dolphinscheduler-ui/src/js/conf/home/pages/monitor/pages/log/_source/list.vue
  36. 157
      dolphinscheduler-ui/src/js/conf/home/pages/monitor/pages/log/index.vue
  37. 9
      dolphinscheduler-ui/src/js/conf/home/router/module/monitor.js
  38. 12
      dolphinscheduler-ui/src/js/conf/home/store/projects/actions.js
  39. 6
      dolphinscheduler-ui/src/js/module/components/secondaryMenu/_source/menu.js
  40. 11
      dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
  41. 10
      dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js

94
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/audit/AuditMessage.java

@ -0,0 +1,94 @@
/*
* 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.api.audit;
import org.apache.dolphinscheduler.common.enums.AuditOperationType;
import org.apache.dolphinscheduler.common.enums.AuditResourceType;
import org.apache.dolphinscheduler.dao.entity.User;
import java.util.Date;
public class AuditMessage {
private User user;
private Date auditDate;
private AuditResourceType resourceType;
private AuditOperationType operation;
private Integer resourceId;
public AuditMessage(User user, Date auditDate, AuditResourceType resourceType, AuditOperationType operation, Integer resourceId) {
this.user = user;
this.auditDate = auditDate;
this.resourceType = resourceType;
this.operation = operation;
this.resourceId = resourceId;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Date getAuditDate() {
return auditDate;
}
public void setAuditDate(Date auditDate) {
this.auditDate = auditDate;
}
public AuditResourceType getResourceType() {
return resourceType;
}
public void setResourceType(AuditResourceType resourceType) {
this.resourceType = resourceType;
}
public AuditOperationType getOperation() {
return operation;
}
public void setOperation(AuditOperationType operation) {
this.operation = operation;
}
public Integer getResourceId() {
return resourceId;
}
public void setResourceId(Integer resourceId) {
this.resourceId = resourceId;
}
@Override
public String toString() {
return "AuditMessage{"
+ "user=" + user
+ ", Date=" + auditDate
+ ", resourceType" + resourceType
+ ", operation=" + operation
+ ", resourceId='" + resourceId + '\'';
}
}

93
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/audit/AuditPublishService.java

@ -0,0 +1,93 @@
/*
* 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.api.audit;
import org.apache.dolphinscheduler.api.configuration.AuditConfiguration;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class AuditPublishService {
private BlockingQueue<AuditMessage> auditMessageQueue = new LinkedBlockingQueue<>();
@Autowired
private List<AuditSubscriber> subscribers;
@Autowired
private AuditConfiguration auditConfiguration;
private static final Logger logger = LoggerFactory.getLogger(AuditPublishService.class);
/**
* create a daemon thread to process the message queue
*/
@PostConstruct
private void init() {
if (auditConfiguration.getEnabled()) {
Thread thread = new Thread(this::doPublish);
thread.setDaemon(true);
thread.setName("Audit-Log-Consume-Thread");
thread.start();
}
}
/**
* publish a new audit message
*
* @param message audit message
*/
public void publish(AuditMessage message) {
if (auditConfiguration.getEnabled() && !auditMessageQueue.offer(message)) {
logger.error("add audit message failed {}", message);
}
}
/**
* subscribers execute the message processor method
*/
private void doPublish() {
AuditMessage message = null;
while (true) {
try {
message = auditMessageQueue.take();
for (AuditSubscriber subscriber : subscribers) {
try {
subscriber.execute(message);
} catch (Exception e) {
logger.error("consume audit message {} failed, error detail {}", message, e);
}
}
} catch (InterruptedException e) {
logger.error("consume audit message failed {}.", message, e);
Thread.currentThread().interrupt();
break;
}
}
}
}

28
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/audit/AuditSubscriber.java

@ -0,0 +1,28 @@
/*
* 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.api.audit;
public interface AuditSubscriber {
/**
* process the audit message
*
* @param message
*/
void execute(AuditMessage message);
}

42
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/audit/AuditSubscriberImpl.java

@ -0,0 +1,42 @@
/*
* 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.api.audit;
import org.apache.dolphinscheduler.dao.entity.AuditLog;
import org.apache.dolphinscheduler.dao.mapper.AuditLogMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class AuditSubscriberImpl implements AuditSubscriber {
@Autowired
private AuditLogMapper logMapper;
@Override
public void execute(AuditMessage message) {
AuditLog auditLog = new AuditLog();
auditLog.setUserId(message.getUser().getId());
auditLog.setResourceType(message.getResourceType().getCode());
auditLog.setOperation(message.getOperation().getCode());
auditLog.setTime(message.getAuditDate());
auditLog.setResourceId(message.getResourceId());
logMapper.insert(auditLog);
}
}

37
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/configuration/AuditConfiguration.java

@ -0,0 +1,37 @@
/*
* 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.api.configuration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@EnableConfigurationProperties
@ConfigurationProperties(value = "audit", ignoreUnknownFields = false)
public class AuditConfiguration {
private boolean enabled;
public boolean getEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}

98
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/AuditLogController.java

@ -0,0 +1,98 @@
/*
* 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.api.controller;
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_AUDIT_LOG_LIST_PAGING;
import org.apache.dolphinscheduler.api.aspect.AccessLogAnnotation;
import org.apache.dolphinscheduler.api.exceptions.ApiException;
import org.apache.dolphinscheduler.api.service.AuditService;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.Constants;
import org.apache.dolphinscheduler.common.enums.AuditOperationType;
import org.apache.dolphinscheduler.common.enums.AuditResourceType;
import org.apache.dolphinscheduler.dao.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import springfox.documentation.annotations.ApiIgnore;
@Api(tags = "AUDIT_LOG_TAG")
@RestController
@RequestMapping("projects/audit")
public class AuditLogController extends BaseController {
@Autowired
AuditService auditService;
/**
* query audit log list paging
*
* @param loginUser login user
* @param pageNo page number
* @param moduleType module type
* @param operationType operation type
* @param startDate start time
* @param endDate end time
* @param userName user name
* @param pageSize page size
* @return audit log content
*/
@ApiOperation(value = "queryAuditLogListPaging", notes = "QUERY_AUDIT_LOG")
@ApiImplicitParams({
@ApiImplicitParam(name = "startDate", value = "START_DATE", type = "String"),
@ApiImplicitParam(name = "endDate", value = "END_DATE", type = "String"),
@ApiImplicitParam(name = "moduleType", value = "MODULE_TYPE", type = "String"),
@ApiImplicitParam(name = "operationType", value = "OPERATION_TYPE", type = "String"),
@ApiImplicitParam(name = "userName", value = "USER_NAME", type = "String"),
@ApiImplicitParam(name = "projectName", value = "PROJECT_NAME", type = "String"),
@ApiImplicitParam(name = "processName", value = "PROCESS_NAME", type = "String"),
@ApiImplicitParam(name = "pageNo", value = "PAGE_NO", required = true, dataType = "Int", example = "1"),
@ApiImplicitParam(name = "pageSize", value = "PAGE_SIZE", required = true, dataType = "Int", example = "20")
})
@GetMapping(value = "/audit-log-list")
@ResponseStatus(HttpStatus.OK)
@ApiException(QUERY_AUDIT_LOG_LIST_PAGING)
@AccessLogAnnotation(ignoreRequestArgs = "loginUser")
public Result queryAuditLogListPaging(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@RequestParam("pageNo") Integer pageNo,
@RequestParam("pageSize") Integer pageSize,
@RequestParam(value = "resourceType", required = false) AuditResourceType resourceType,
@RequestParam(value = "operationType", required = false) AuditOperationType operationType,
@RequestParam(value = "startDate", required = false) String startDate,
@RequestParam(value = "endDate", required = false) String endDate,
@RequestParam(value = "userName", required = false) String userName) {
Result result = checkPageParams(pageNo, pageSize);
if (!result.checkResult()) {
return result;
}
result = auditService.queryLogListPaging(loginUser, resourceType, operationType, startDate, endDate, userName, pageNo, pageSize);
return result;
}
}

76
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/dto/AuditDto.java

@ -0,0 +1,76 @@
/*
* 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.api.dto;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
public class AuditDto {
private String userName;
private String resource;
private String operation;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date time;
private String resourceName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getResource() {
return resource;
}
public void setResource(String resource) {
this.resource = resource;
}
public String getOperation() {
return operation;
}
public void setOperation(String operation) {
this.operation = operation;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
public String getResourceName() {
return resourceName;
}
public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}
}

3
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java

@ -319,6 +319,9 @@ public enum Status {
KERBEROS_STARTUP_STATE(100001, "get kerberos startup state error", "获取kerberos启动状态错误"),
// audit log
QUERY_AUDIT_LOG_LIST_PAGING(10057, "query resources list paging", "分页查询资源列表错误"),
//plugin
PLUGIN_NOT_A_UI_COMPONENT(110001, "query plugin error, this plugin has no UI component", "查询插件错误,此插件无UI组件"),
QUERY_PLUGINS_RESULT_IS_NULL(110002, "query plugins result is null", "查询插件为空"),

57
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/AuditService.java

@ -0,0 +1,57 @@
/*
* 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.api.service;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.enums.AuditOperationType;
import org.apache.dolphinscheduler.common.enums.AuditResourceType;
import org.apache.dolphinscheduler.dao.entity.User;
/**
* audit information service
*/
public interface AuditService {
/**
* add new audit record
*
* @param user login user
* @param resourceType resource type
* @param resourceId resource id
* @param operation operation type
*/
void addAudit(User user, AuditResourceType resourceType, Integer resourceId, AuditOperationType operation);
/**
* query audit log list
*
* @param loginUser login user
* @param resourceType resource type
* @param operationType operation type
* @param startTime start time
* @param endTime end time
* @param userName query user name
* @param pageNo page number
* @param pageSize page size
* @return audit log string
*/
Result queryLogListPaging(User loginUser, AuditResourceType resourceType,
AuditOperationType operationType, String startTime,
String endTime, String userName,
Integer pageNo, Integer pageSize);
}

137
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/AuditServiceImpl.java

@ -0,0 +1,137 @@
/*
* 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.api.service.impl;
import org.apache.dolphinscheduler.api.audit.AuditMessage;
import org.apache.dolphinscheduler.api.audit.AuditPublishService;
import org.apache.dolphinscheduler.api.dto.AuditDto;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.service.AuditService;
import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.Constants;
import org.apache.dolphinscheduler.common.enums.AuditOperationType;
import org.apache.dolphinscheduler.common.enums.AuditResourceType;
import org.apache.dolphinscheduler.dao.entity.AuditLog;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.mapper.AuditLogMapper;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@Service
public class AuditServiceImpl extends BaseServiceImpl implements AuditService {
@Autowired
private AuditLogMapper auditLogMapper;
@Autowired
private AuditPublishService publishService;
/**
* add new audit log
*
* @param user login user
* @param resourceType resource type
* @param resourceId resource id
* @param operation operation type
*/
@Override
public void addAudit(User user, AuditResourceType resourceType, Integer resourceId, AuditOperationType operation) {
publishService.publish(new AuditMessage(user, new Date(), resourceType, operation, resourceId));
}
/**
* query audit log paging
*
* @param loginUser login user
* @param resourceType resource type
* @param operationType operation type
* @param startDate start time
* @param endDate end time
* @param userName query user name
* @param pageNo page number
* @param pageSize page size
* @return audit log string data
*/
@Override
public Result queryLogListPaging(User loginUser, AuditResourceType resourceType,
AuditOperationType operationType, String startDate,
String endDate, String userName,
Integer pageNo, Integer pageSize) {
Result result = new Result();
Map<String, Object> checkAndParseDateResult = checkAndParseDateParameters(startDate, endDate);
Status resultEnum = (Status) checkAndParseDateResult.get(Constants.STATUS);
if (resultEnum != Status.SUCCESS) {
putMsg(result,resultEnum);
return result;
}
int[] resourceArray = null;
if (resourceType != null) {
resourceArray = new int[]{resourceType.getCode()};
}
int[] opsArray = null;
if (operationType != null) {
opsArray = new int[]{operationType.getCode()};
}
Date start = (Date) checkAndParseDateResult.get(Constants.START_TIME);
Date end = (Date) checkAndParseDateResult.get(Constants.END_TIME);
Page<AuditLog> page = new Page<>(pageNo, pageSize);
IPage<AuditLog> logIPage = auditLogMapper.queryAuditLog(page, resourceArray, opsArray, userName, start, end);
List<AuditLog> logList = logIPage != null ? logIPage.getRecords() : new ArrayList<>();
PageInfo<AuditDto> pageInfo = new PageInfo<>(pageNo, pageSize);
List<AuditDto> auditDtos = logList.stream().map(this::transformAuditLog).collect(Collectors.toList());
pageInfo.setTotal((int) (auditDtos != null ? auditDtos.size() : 0L));
pageInfo.setTotalList(auditDtos);
result.setData(pageInfo);
putMsg(result, Status.SUCCESS);
return result;
}
/**
* transform AuditLog to AuditDto
*
* @param auditLog audit log
* @return audit dto
*/
private AuditDto transformAuditLog(AuditLog auditLog) {
AuditDto auditDto = new AuditDto();
String resourceType = AuditResourceType.of(auditLog.getResourceType()).getMsg();
auditDto.setResource(resourceType);
auditDto.setOperation(AuditOperationType.of(auditLog.getOperation()).getMsg());
auditDto.setUserName(auditLog.getUserName());
auditDto.setResourceName(auditLogMapper.queryResourceNameByType(resourceType, auditLog.getResourceId()));
auditDto.setTime(auditLog.getTime());
return auditDto;
}
}

3
dolphinscheduler-api/src/main/resources/application.yaml

@ -101,6 +101,9 @@ registry:
block-until-connected: 600ms
digest: ~
audit:
enabled: false
# Override by profile
---

3
dolphinscheduler-api/src/main/resources/i18n/messages.properties

@ -282,3 +282,6 @@ DELETE_PROCESS_DEFINITION_VERSION_NOTES=delete process definition version
QUERY_PROCESS_DEFINITION_VERSIONS_NOTES=query process definition versions
SWITCH_PROCESS_DEFINITION_VERSION_NOTES=switch process definition version
VERSION=version
AUDIT_LOG_TAG=audit log related operation
MODULE_TYPE=module type
OPERATION_TYPE=operation type

4
dolphinscheduler-api/src/main/resources/i18n/messages_en_US.properties

@ -340,3 +340,7 @@ SWITCH_PROCESS_DEFINITION_VERSION_NOTES=switch process definition version
VERSION=version
TASK_GROUP_QUEUEID=task group queue id
TASK_GROUP_QUEUE_PRIORITY=task group queue priority
QUERY_AUDIT_LOG=query audit log
AUDIT_LOG_TAG=audit log related operation
MODULE_TYPE=module type
OPERATION_TYPE=operation type

4
dolphinscheduler-api/src/main/resources/i18n/messages_zh_CN.properties

@ -336,3 +336,7 @@ SWITCH_PROCESS_DEFINITION_VERSION_NOTES=切换流程版本
VERSION=版本号
TASK_GROUP_QUEUEID=任务组队列id
TASK_GROUP_QUEUE_PRIORITY=任务队列优先级
QUERY_AUDIT_LOG=查询审计日志
AUDIT_LOG_TAG=审计日志执行相关操作
MODULE_TYPE=模块类型
OPERATION_TYPE=操作类型

49
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/audit/AuditSubscriberTest.java

@ -0,0 +1,49 @@
/*
* 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.api.audit;
import org.apache.dolphinscheduler.common.enums.AuditOperationType;
import org.apache.dolphinscheduler.common.enums.AuditResourceType;
import org.apache.dolphinscheduler.dao.entity.AuditLog;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.mapper.AuditLogMapper;
import java.util.Date;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class AuditSubscriberTest {
@Mock
private AuditLogMapper logMapper;
@InjectMocks
private AuditSubscriberImpl auditSubscriber;
@Test
public void testExecute() {
Mockito.when(logMapper.insert(Mockito.any(AuditLog.class))).thenReturn(1);
auditSubscriber.execute(new AuditMessage(new User(), new Date(), AuditResourceType.USER_MODULE, AuditOperationType.CREATE, 1));
}
}

40
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/configuration/AuditConfigurationTest.java

@ -0,0 +1,40 @@
/*
* 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.api.configuration;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ActiveProfiles("audit")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = AuditConfiguration.class)
public class AuditConfigurationTest {
@Autowired
private AuditConfiguration auditConfiguration;
@Test
public void isAuditGlobalControlSwitch() {
Assert.assertTrue(auditConfiguration.getEnabled());
}
}

61
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/AuditLogControllerTest.java

@ -0,0 +1,61 @@
/*
* 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.api.controller;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.utils.JSONUtils;
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
* audit log controller test
*/
public class AuditLogControllerTest extends AbstractControllerTest {
private static Logger logger = LoggerFactory.getLogger(AuditLogControllerTest.class);
@Test
public void testQueryAuditLogListPaging() throws Exception {
MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
paramsMap.add("pageNo", "1");
paramsMap.add("pageSize", "10");
MvcResult mvcResult = mockMvc.perform(get("/projects/audit/audit-log-list")
.header(SESSION_ID, sessionId)
.params(paramsMap))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class);
Assert.assertEquals(Status.SUCCESS.getCode(),result.getCode().intValue());
logger.info(mvcResult.getResponse().getContentAsString());
}
}

91
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/AuditServiceTest.java

@ -0,0 +1,91 @@
/*
* 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.api.service;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.service.impl.AuditServiceImpl;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.utils.DateUtils;
import org.apache.dolphinscheduler.dao.entity.AuditLog;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.mapper.AuditLogMapper;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
/**
* audit service test
*/
@RunWith(MockitoJUnitRunner.class)
public class AuditServiceTest {
private static final Logger logger = LoggerFactory.getLogger(AuditServiceTest.class);
@InjectMocks
private AuditServiceImpl auditService;
@Mock
private AuditLogMapper auditLogMapper;
@Test
public void testQueryLogListPaging() {
Date start = DateUtils.getScheduleDate("2020-11-01 00:00:00");
Date end = DateUtils.getScheduleDate("2020-11-02 00:00:00");
IPage<AuditLog> page = new Page<>(1, 10);
page.setRecords(getLists());
page.setTotal(1L);
when(auditLogMapper.queryAuditLog(Mockito.any(Page.class), Mockito.any(), Mockito.any(),
Mockito.eq(""), eq(start), eq(end)))
.thenReturn(page);
Result result = auditService.queryLogListPaging(new User(), null, null, "2020-11-01 00:00:00", "2020-11-02 00:00:00", "", 1, 10);
logger.info(result.toString());
Assert.assertEquals(Status.SUCCESS.getCode(), (int) result.getCode());
}
private List<AuditLog> getLists() {
List<AuditLog> list = new ArrayList<>();
list.add(getAuditLog());
return list;
}
private AuditLog getAuditLog() {
AuditLog auditLog = new AuditLog();
auditLog.setUserName("testName");
auditLog.setOperation(0);
auditLog.setResourceType(0);
return auditLog;
}
}

3
dolphinscheduler-api/src/test/resources/application.yaml

@ -26,3 +26,6 @@ spring:
registry:
type: zookeeper
audit:
enabled: true

62
dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/AuditOperationType.java

@ -0,0 +1,62 @@
/*
* 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.common.enums;
import java.util.HashMap;
/**
* Audit Operation type
*/
public enum AuditOperationType {
CREATE(0, "CREATE"),
READ(1, "READ"),
UPDATE(2, "UPDATE"),
DELETE(3, "DELETE");
private final int code;
private final String enMsg;
private static HashMap<Integer, AuditOperationType> AUDIT_OPERATION_MAP = new HashMap<>();
static {
for (AuditOperationType operationType : AuditOperationType.values()) {
AUDIT_OPERATION_MAP.put(operationType.code, operationType);
}
}
AuditOperationType(int code, String enMsg) {
this.code = code;
this.enMsg = enMsg;
}
public static AuditOperationType of(int status) {
if (AUDIT_OPERATION_MAP.containsKey(status)) {
return AUDIT_OPERATION_MAP.get(status);
}
throw new IllegalArgumentException("invalid audit operation type code " + status);
}
public int getCode() {
return code;
}
public String getMsg() {
return enMsg;
}
}

60
dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/AuditResourceType.java

@ -0,0 +1,60 @@
/*
* 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.common.enums;
import java.util.HashMap;
/**
* Audit Module type
*/
public enum AuditResourceType {
// TODO: add other audit resource enums
USER_MODULE(0, "USER"),
PROJECT_MODULE(1, "PROJECT");
private final int code;
private final String enMsg;
private static HashMap<Integer, AuditResourceType> AUDIT_RESOURCE_MAP = new HashMap<>();
static {
for (AuditResourceType auditResourceType : AuditResourceType.values()) {
AUDIT_RESOURCE_MAP.put(auditResourceType.code, auditResourceType);
}
}
AuditResourceType(int code, String enMsg) {
this.code = code;
this.enMsg = enMsg;
}
public int getCode() {
return this.code;
}
public String getMsg() {
return this.enMsg;
}
public static AuditResourceType of(int status) {
if (AUDIT_RESOURCE_MAP.containsKey(status)) {
return AUDIT_RESOURCE_MAP.get(status);
}
throw new IllegalArgumentException("invalid audit resource type code " + status);
}
}

116
dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/AuditLog.java

@ -0,0 +1,116 @@
/*
* 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.dao.entity;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
@TableName("t_ds_audit_log")
public class AuditLog {
/**
* id
*/
@TableId(value = "id", type = IdType.AUTO)
private int id;
/**
* user id
*/
private Integer userId;
/**
* resource type
*/
private Integer resourceType;
/**
* operation type
*/
private Integer operation;
/**
* resource id
*/
private Integer resourceId;
/**
* user name
*/
@TableField(exist = false)
private String userName;
/**
* operation time
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date time;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public Integer getResourceType() {
return resourceType;
}
public void setResourceType(Integer resourceType) {
this.resourceType = resourceType;
}
public Integer getOperation() {
return operation;
}
public void setOperation(Integer operation) {
this.operation = operation;
}
public Integer getResourceId() {
return resourceId;
}
public void setResourceId(Integer resourceId) {
this.resourceId = resourceId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
}

42
dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/AuditLogMapper.java

@ -0,0 +1,42 @@
/*
* 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.dao.mapper;
import org.apache.dolphinscheduler.dao.entity.AuditLog;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
/**
* auditlog mapper interface
*/
public interface AuditLogMapper extends BaseMapper<AuditLog> {
IPage<AuditLog> queryAuditLog(IPage<AuditLog> page,
@Param("resourceType") int[] resourceArray,
@Param("operationType") int[] operationType,
@Param("userName") String userName,
@Param("startDate") Date startDate,
@Param("endDate") Date endDate);
String queryResourceNameByType(@Param("resourceType") String resourceType,
@Param("resourceId") Integer resourceId);
}

64
dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/AuditLogMapper.xml

@ -0,0 +1,64 @@
<?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.
-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="org.apache.dolphinscheduler.dao.mapper.AuditLogMapper">
<sql id="baseSql">
id, user_id, resource_type, operation, resource_id, time
</sql>
<sql id="baseSqlV2">
${alias}.id, ${alias}.user_id, ${alias}.resource_type, ${alias}.operation, ${alias}.resource_id, ${alias}.time
</sql>
<select id="queryAuditLog" resultType="org.apache.dolphinscheduler.dao.entity.AuditLog">
select
<include refid="baseSqlV2">
<property name="alias" value="log"/>
</include>
,
u.user_name as user_name
from t_ds_audit_log log
join t_ds_user u on log.user_id = u.id
where 1 = 1
<if test="startDate != null">
and log.time > #{startDate} and log.time <![CDATA[ <=]]> #{endDate}
</if>
<if test="resourceType != null and resourceType.length > 0">
and log.resource_type in
<foreach collection="resourceType" index="index" item="i" open="(" separator="," close=")">
#{i}
</foreach>
</if>
<if test="operationType != null and operationType.length > 0">
and log.operation in
<foreach collection="operationType" index="index" item="j" open="(" separator="," close=")">
#{j}
</foreach>
</if>
<if test="userName != null and userName != ''">
and u.user_name = #{userName}
</if>
order by log.time desc
</select>
<select id="queryResourceNameByType" resultType="String">
<if test="resourceType != null and resourceType == 'USER'">
select user_name from t_ds_user where id = #{resourceId}
</if>
</select>
</mapper>

15
dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql

@ -1078,3 +1078,18 @@ CREATE TABLE t_ds_task_group
update_time datetime DEFAULT NULL ,
PRIMARY KEY(id)
);
-- ----------------------------
-- Table structure for t_ds_alert_plugin_instance
-- ----------------------------
DROP TABLE IF EXISTS t_ds_audit_log;
CREATE TABLE t_ds_audit_log
(
id int(11) NOT NULL AUTO_INCREMENT,
user_id int(11) NOT NULL,
resource_type int(11) NOT NULL,
operation int(11) NOT NULL,
time timestamp NULL DEFAULT CURRENT_TIMESTAMP,
resource_id int(11) NOT NULL,
PRIMARY KEY (id)
);

14
dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql

@ -1063,3 +1063,17 @@ CREATE TABLE `t_ds_task_group` (
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY(`id`)
) ENGINE= INNODB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8;
-- ----------------------------
-- Table structure for t_ds_audit_log
-- ----------------------------
DROP TABLE IF EXISTS `t_ds_audit_log`;
CREATE TABLE `t_ds_audit_log` (
`id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT'key',
`user_id` int(11) NOT NULL COMMENT 'user id',
`resource_type` int(11) NOT NULL COMMENT 'resource type',
`operation` int(11) NOT NULL COMMENT 'operation',
`time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT 'create time',
`resource_id` int(11) NULL DEFAULT NULL COMMENT 'resource id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT= 1 DEFAULT CHARSET=utf8;

14
dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql

@ -1062,3 +1062,17 @@ CREATE TABLE t_ds_task_group (
update_time timestamp DEFAULT NULL ,
PRIMARY KEY(id)
);
-- ----------------------------
-- Table structure for t_ds_audit_log
-- ----------------------------
DROP TABLE IF EXISTS t_ds_audit_log;
CREATE TABLE t_ds_audit_log (
id serial NOT NULL,
user_id int NOT NULL,
resource_type int NOT NULL,
operation int NOT NULL,
time timestamp DEFAULT NULL ,
resource_id int NOT NULL,
PRIMARY KEY (id)
);

14
dolphinscheduler-dao/src/main/resources/sql/upgrade/2.0.0_schema/mysql/dolphinscheduler_ddl.sql

@ -368,6 +368,20 @@ CREATE TABLE `t_ds_worker_group` (
UNIQUE KEY `name_unique` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for t_ds_audit_log
-- ----------------------------
DROP TABLE IF EXISTS `t_ds_audit_log`;
CREATE TABLE `t_ds_audit_log` (
`id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT'key',
`user_id` int(11) NOT NULL COMMENT 'user id',
`resource_type` int(11) NOT NULL COMMENT 'resource type',
`operation` int(11) NOT NULL COMMENT 'operation',
`time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT 'create time',
`resource_id` int(11) NULL DEFAULT NULL COMMENT 'resource id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT= 1 DEFAULT CHARSET=utf8;
-- t_ds_command
alter table t_ds_command change process_definition_id process_definition_code bigint(20) NOT NULL COMMENT 'process definition code';
alter table t_ds_command add environment_code bigint(20) DEFAULT '-1' COMMENT 'environment code' AFTER worker_group;

10
dolphinscheduler-dao/src/main/resources/sql/upgrade/2.0.0_schema/postgresql/dolphinscheduler_ddl.sql

@ -318,6 +318,16 @@ BEGIN
CONSTRAINT name_unique UNIQUE (name)
)';
EXECUTE 'CREATE TABLE IF NOT EXISTS '|| quote_ident(v_schema) ||'."t_ds_audit_log" (
id serial NOT NULL,
user_id int NOT NULL,
resource_type int NOT NULL,
operation int NOT NULL,
time timestamp DEFAULT NULL ,
resource_id int NOT NULL,
PRIMARY KEY (id)
)';
return 'Success!';
exception when others then
---Raise EXCEPTION '(%)',SQLERRM;

70
dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/AuditLogMapperTest.java

@ -0,0 +1,70 @@
/*
* 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.dao.mapper;
import org.apache.dolphinscheduler.dao.BaseDaoTest;
import org.apache.dolphinscheduler.dao.entity.AuditLog;
import java.util.Date;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
public class AuditLogMapperTest extends BaseDaoTest {
@Autowired
AuditLogMapper logMapper;
/**
* insert
* @return
*/
private void insertOne() {
AuditLog auditLog = new AuditLog();
auditLog.setUserId(1);
auditLog.setTime(new Date());
auditLog.setResourceType(0);
auditLog.setOperation(0);
auditLog.setResourceId(0);
logMapper.insert(auditLog);
}
/**
* test page query
*/
@Test
public void testQueryAuditLog() {
insertOne();
Page<AuditLog> page = new Page<>(1, 3);
int[] resourceType = new int[0];
int[] operationType = new int[0];
IPage<AuditLog> logIPage = logMapper.queryAuditLog(page, resourceType, operationType, "", null, null);
Assert.assertNotEquals(logIPage.getTotal(), 0);
}
@Test
public void testQueryResourceNameByType() {
String resourceName = logMapper.queryResourceNameByType("USER", 1);
Assert.assertEquals("admin", resourceName);
}
}

3
dolphinscheduler-standalone-server/src/main/resources/application.yaml

@ -159,6 +159,9 @@ management:
tags:
application: ${spring.application.name}
audit:
enabled: true
# Override by profile
---
spring:

127
dolphinscheduler-ui/src/js/conf/home/pages/monitor/pages/_source/conditions/audit/auditLog.vue

@ -0,0 +1,127 @@
/*
* 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.
*/
<template>
<m-conditions>
<template slot="search-group">
<div class="list">
<el-button size="mini" @click="_ckQuery" icon="el-icon-search"></el-button>
</div>
<div class="list">
<el-date-picker
style="width: 310px"
v-model="dataTime"
size="mini"
@change="_onChangeStartStop"
type="datetimerange"
range-separator="-"
:start-placeholder="$t('startDate')"
:end-placeholder="$t('endDate')"
value-format="yyyy-MM-dd HH:mm:ss">
</el-date-picker>
</div>
<div class="list">
<el-select style="width: 140px;" @change="_onChangeResource" :value="searchParams.resourceType" :placeholder="$t('Resource Type')" size="mini">
<el-option
v-for="module in resourceTypeList"
:key="module.label"
:value="module.code"
:label="module.label">
</el-option>
</el-select>
</div>
<div class="list">
<el-select style="width: 140px;" @change="_onChangeOperation" :value="searchParams.operationType" :placeholder="$t('Operation')" size="mini">
<el-option
v-for="operation in operationTypeList"
:key="operation.label"
:value="operation.code"
:label="operation.label">
</el-option>
</el-select>
</div>
<div class="list">
<el-input v-model="searchParams.userName" @keyup.enter.native="_ckQuery" style="width: 140px;" size="mini" :placeholder="$t('User Name')"></el-input>
</div>
</template>
</m-conditions>
</template>
<script>
import _ from 'lodash'
import { resourceType, operationType } from './common'
import mConditions from '@/module/components/conditions/conditions'
export default {
name: 'monitor-log-conditions',
data () {
return {
// state(list)
resourceTypeList: resourceType,
operationTypeList: operationType,
searchParams: {
// resource type
resourceType: '',
// operation
operationType: '',
// start date
startDate: '',
// end date
endDate: ''
},
dataTime: []
}
},
props: {},
methods: {
_ckQuery () {
this.$emit('on-query', this.searchParams)
},
/**
* change times
*/
_onChangeStartStop (val) {
this.searchParams.startDate = val[0]
this.searchParams.endDate = val[1]
this.dataTime[0] = val[0]
this.dataTime[1] = val[1]
},
/**
* change resource
*/
_onChangeResource (val) {
this.searchParams.resourceType = val
},
/**
* change operation
*/
_onChangeOperation (val) {
this.searchParams.operationType = val
}
},
watch: {
},
created () {
// Routing parameter merging
if (!_.isEmpty(this.$route.query)) {
this.searchParams = _.assign(this.searchParams, this.$route.query)
}
},
mounted () {
},
computed: {
},
components: { mConditions }
}
</script>

60
dolphinscheduler-ui/src/js/conf/home/pages/monitor/pages/_source/conditions/audit/common.js

@ -0,0 +1,60 @@
/*
* 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.
*/
import i18n from '@/module/i18n'
/**
* Module code table
*/
const resourceType = [
{
code: '',
label: `${i18n.$t('Resource Type')}`
}, {
code: 'USER_MODULE',
label: `${i18n.$t('User Audit')}`
}, {
code: 'PROJECT_MODULE',
label: `${i18n.$t('Project Audit')}`
}
]
/**
* Operation code table
*/
const operationType = [
{
code: '',
label: `${i18n.$t('All Operations')}`
}, {
code: 'CREATE',
label: `${i18n.$t('Create Operation')}`
}, {
code: 'UPDATE',
label: `${i18n.$t('Update Operation')}`
}, {
code: 'DELETE',
label: `${i18n.$t('Delete Operation')}`
}, {
code: 'READ',
label: `${i18n.$t('Read Operation')}`
}
]
export {
resourceType, operationType
}

24
dolphinscheduler-ui/src/js/conf/home/pages/monitor/pages/_source/conditions/index.vue

@ -0,0 +1,24 @@
/*
* 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.
*/
<template>
<router-view></router-view>
</template>
<script>
export default {
name: 'monitor-conditions-index'
}
</script>

72
dolphinscheduler-ui/src/js/conf/home/pages/monitor/pages/log/_source/list.vue

@ -0,0 +1,72 @@
/*
* 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.
*/
<template>
<div class="list-model">
<div class="table-box">
<el-table :data="list" size="mini" style="width: 100%">
<el-table-column type="index" :label="$t('#')" width="50"></el-table-column>
<el-table-column prop="userName" :label="$t('User Name')"></el-table-column>
<el-table-column prop="resource" :label="$t('Resource Type')"></el-table-column>
<el-table-column prop="resourceName" :label="$t('Project Name')"></el-table-column>
<el-table-column prop="operation" :label="$t('Operation')">
<template slot-scope="scope">
<span>{{scope.row.operation | filterNull}}</span>
</template>
</el-table-column>
<el-table-column :label="$t('Create Time')" min-width="120">
<template slot-scope="scope">
<span>{{scope.row.time | formatDate}}</span>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script>
export default {
name: 'audit-list',
data () {
return {
list: []
}
},
props: {
logList: Array,
pageNo: Number,
pageSize: Number
},
methods: {
_edit (item) {
this.$emit('on-edit', item)
}
},
watch: {
logList (a) {
this.list = []
setTimeout(() => {
this.list = a
})
}
},
created () {
this.list = this.logList
},
mounted () {
},
components: { }
}
</script>

157
dolphinscheduler-ui/src/js/conf/home/pages/monitor/pages/log/index.vue

@ -0,0 +1,157 @@
/*
* 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.
*/
<template>
<m-list-construction :title="$t('Audit Log')">
<template slot="conditions">
<m-log-conditions @on-query="_onQuery"></m-log-conditions>
</template>
<template slot="content">
<template v-if="logList.length || total>0">
<m-list @on-edit="_onEdit"
:log-list="logList"
:page-no="searchParams.pageNo"
:page-size="searchParams.pageSize">
</m-list>
<div class="page-box">
<el-pagination
background
@current-change="_page"
@size-change="_pageSize"
:page-size="searchParams.pageSize"
:current-page.sync="searchParams.pageNo"
:page-sizes="[10, 30, 50]"
layout="sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</template>
<template v-if="!logList.length && total<=0">
<m-no-data></m-no-data>
</template>
<m-spin :is-spin="isLoading" :is-left="isLeft"></m-spin>
</template>
</m-list-construction>
</template>
<script>
import _ from 'lodash'
import { mapActions } from 'vuex'
import mList from './_source/list'
import store from '@/conf/home/store'
import mSpin from '@/module/components/spin/spin'
import mNoData from '@/module/components/noData/noData'
import listUrlParamHandle from '@/module/mixin/listUrlParamHandle'
import mListConstruction from '@/module/components/listConstruction/listConstruction'
import mLogConditions from '@/conf/home/pages/monitor/pages/_source/conditions/audit/auditLog'
export default {
name: 'audit-log-index',
data () {
return {
total: null,
isLoading: true,
logList: [],
searchParams: {
pageSize: 10,
pageNo: 1,
// resource type
resourceType: '',
// operation
operationType: '',
// start date
startDate: '',
// end date
endDate: '',
// operator
userName: ''
},
isLeft: true,
// isEffective: 1,
isADMIN: store.state.user.userInfo.userType === 'ADMIN_USER',
item: {}
}
},
mixins: [listUrlParamHandle],
props: {},
methods: {
...mapActions('projects', ['getAuditLogList']),
/**
* click query
*/
_onQuery (o) {
this.searchParams = _.assign(this.searchParams, o)
this.searchParams.pageNo = 1
},
_page (val) {
this.searchParams.pageNo = val
},
_pageSize (val) {
this.searchParams.pageSize = val
},
_onUpdate () {
this._debounceGET()
},
close () {
},
_getList (flag) {
this.isLoading = !flag
this.getAuditLogList(this.searchParams).then(res => {
if (this.searchParams.pageNo > 1 && res.totalList.length === 0) {
this.searchParams.pageNo = this.searchParams.pageNo - 1
} else {
this.logList = []
this.logList = res.totalList
this.total = res.total
this.isLoading = false
}
}).catch(e => {
this.isLoading = false
})
},
_debounceGET: _.debounce(function (flag) {
if (Number(sessionStorage.getItem('isLeft')) === 0) {
this.isLeft = false
} else {
this.isLeft = true
}
this._getList(flag)
}, 100, {
leading: false,
trailing: true
})
},
watch: {
// router
'$route' (a) {
// url no params get instance list
this.searchParams.pageNo = _.isEmpty(a.query) ? 1 : a.query.pageNo
}
},
created () {
},
mounted () {
// Cycle acquisition status
this.setIntervalP = setInterval(() => {
this._debounceGET('false')
}, 90000)
},
beforeDestroy () {
clearInterval(this.setIntervalP)
sessionStorage.setItem('isLeft', 1)
},
components: { mList, mListConstruction, mSpin, mNoData, mLogConditions }
}
</script>

9
dolphinscheduler-ui/src/js/conf/home/router/module/monitor.js

@ -92,6 +92,15 @@ const monitor = [
title: 'statistics',
refreshInSwitchedTab: config.refreshInSwitchedTab
}
},
{
path: '/monitor/audit/log',
name: 'audit-log',
component: resolve => require(['../../pages/monitor/pages/log/index'], resolve),
meta: {
title: 'audit-log',
refreshInSwitchedTab: config.refreshInSwitchedTab
}
}
]
}

12
dolphinscheduler-ui/src/js/conf/home/store/projects/actions.js

@ -137,5 +137,17 @@ export default {
reject(e)
})
})
},
/**
* Get audit log list
*/
getAuditLogList ({ state }, payload) {
return new Promise((resolve, reject) => {
io.get('projects/audit/audit-log-list', payload, res => {
resolve(res.data)
}).catch(e => {
reject(e)
})
})
}
}

6
dolphinscheduler-ui/src/js/module/components/secondaryMenu/_source/menu.js

@ -298,6 +298,12 @@ const menu = {
path: 'statistics',
id: 0,
enabled: true
},
{
name: 'Audit Log',
path: 'audit-log',
id: 1,
enabled: true
}
]
}

11
dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js

@ -802,6 +802,17 @@ export default {
'Priority not empty': 'The value of priority can not be empty',
'Priority must be number': 'The value of priority should be number',
'Please select task name': 'Please select a task name',
'Audit Log': 'Audit Log',
'Resource Type': 'resource type',
'All Types': 'all types',
'All Modules': 'all modules',
'All Operations': 'all operations',
'User Audit': 'user management audit',
'Project Audit': 'project management audit',
'Create Operation': 'create',
'Update Operation': 'update',
'Delete Operation': 'delete',
'Read Operation': 'read',
'Process State': 'Process State',
'Upstream Tasks': 'Upstream Tasks',
'and {n} more': ' and {n} more',

10
dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js

@ -804,6 +804,16 @@ export default {
'Priority not empty': '优先级不能为空',
'Priority must be number': '优先级必须是数值',
'Please select task name': '请选择节点名称',
'Audit Log': '审计日志',
'Resource Type': '资源类型',
'All Types': '所有类型',
'All Operations': '所有操作',
'User Audit': '用户管理审计',
'Project Audit': '项目管理审计',
'Create Operation': '创建',
'Update Operation': '更新',
'Delete Operation': '删除',
'Read Operation': '读取',
'Process State': '工作流状态',
'Upstream Tasks': '上游任务',
'and {n} more': '{n}',

Loading…
Cancel
Save