-
-
Notifications
You must be signed in to change notification settings - Fork 10.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add apollo audit log common solution backend #4985
Changes from all commits
4911b87
b7b7b61
687b73b
d1b4574
57eb3d6
83e7021
d291b7d
bf4105d
4031cc2
85a2403
b556305
668a34e
ff6fb0e
ac42630
154a17b
7608549
721cd4f
50a1ee5
a6e7b3c
ca7469e
21b061f
1da08c3
7be4d34
c43217e
bae4aad
39491ef
c345830
87ef435
4ce1f9d
8a45abf
beecd44
c73c8d7
0e4f852
2dc02c0
bbdd361
d0654b3
f0eaa34
ba3c354
ad324de
add5f0d
a154f53
62cbdc9
b7a2c25
08f6fb9
a6ff3a6
37a8148
ee5c271
1e04137
93b2907
36f0d75
37c1458
5430d0b
c670758
f4de3b3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
# Features: Apollo-Audit-Log | ||
|
||
This module provides audit log functions for other Apollo modules. | ||
|
||
Only apolloconfig's developer need to read it, | ||
|
||
apolloconfig's user doesn't need. | ||
|
||
## How to enable/disable | ||
|
||
We can switch this module freely by properties: | ||
|
||
by adding properties to application.properties: | ||
|
||
``` | ||
# true: enabled the new feature of audit log | ||
# false/missing: disable it | ||
apollo.audit.log.enabled = true | ||
``` | ||
|
||
## How to generate audit log | ||
|
||
### Append an AuditLog | ||
|
||
Through an AuditLog, we have the ability to record **Who, When, Why, Where, What and How** operates something. | ||
|
||
We can do this by using annotations: | ||
|
||
```java | ||
@ApolloAuditLog(type=OpType.CREATE,name="App.create") | ||
public App create() { | ||
// ... | ||
} | ||
``` | ||
|
||
Through this, an AuditLog will be created and its AuditScope will be activated during the execution of this method. | ||
|
||
Equally, we can use ApolloAuditLogApi to do this manually: | ||
|
||
```java | ||
public App create() { | ||
try(AutoCloseable auditScope = api.appendAuditLog(type, name)) { | ||
// ... | ||
} | ||
} | ||
/**************OR**************/ | ||
public App create() { | ||
Autocloseable auditScope = api.appendAuditLog(type, name); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. try with resources? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. try with resources? |
||
// ... | ||
auditScope.close(); | ||
} | ||
``` | ||
|
||
The only thing you need to pay attention to is that you need to close this scope manually~ | ||
|
||
### Append DataInfluence | ||
|
||
This function can also be implemented automatically and manually. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sometimes there is not DataInfluence, we should tell developer about it. |
||
|
||
There is a corresponding relationship between DataInfluences and a certain AuditLog, and they are caused by this AuditLog. But not all AuditLogs will generate DataInfluences! | ||
|
||
#### Mark which data change | ||
|
||
First, we need to add audit-bean-definition to class of the entity you want to audit: | ||
|
||
```java | ||
@ApolloAuditLogDataInfluenceTable(tableName = "App") | ||
public class App extends BaseEntity { | ||
@ApolloAuditLogDataInfluenceTableField(fieldName = "Name") | ||
private String name; | ||
private String orgId; | ||
} | ||
``` | ||
|
||
In class App, we define that its data-influence table' name is "App", the field "name" needs to be audited and its audit field name in the table "App" is "Name". The field "orgId" is no need to be audited. | ||
|
||
Second, use API's method to append it: | ||
|
||
Actually we don't need to manually call it. We can depend on the DomainEvents that pre-set in BaseEntity: | ||
|
||
```java | ||
@DomainEvents | ||
public Collection<ApolloAuditLogDataInfluenceEvent> domainEvents() { | ||
return Collections.singletonList(new ApolloAuditLogDataInfluenceEvent(this.getClass(), this)); | ||
} | ||
``` | ||
|
||
And this will call appendDataInfluences automatically by the listener. | ||
|
||
#### Manually | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe should describe how to verify the audit log work too... For example, which table's data change, or how to check it by UI |
||
|
||
```java | ||
/** | ||
* Append DataInfluences by a list of entities needs to be audited, and their | ||
* audit-bean-definition. | ||
*/ | ||
ApolloAuditLogApi.appendDataInfluences(List<Object> entities, Class<?> beanDefinition); | ||
``` | ||
|
||
Just call the api method in an active scope, the data influences will combine with the log automatically. | ||
|
||
```java | ||
public App create() { | ||
try(AutoCloseable auditScope = api.appendAuditLog(type, name)) { | ||
// ... | ||
api.appendDataInfluences(appList, App.class); | ||
// or. | ||
api.appendDataInfluence("App","10001","Name","xxx"); | ||
} | ||
} | ||
``` | ||
|
||
#### some tricky situations | ||
|
||
Yet, sometimes we can't catch the domain events like some operations that directly change database fields. We can use annotations to catch the input parameters: | ||
|
||
```java | ||
@ApolloAuditLog(type=OpType.DELETE,name="AppNamespace.batchDeleteByAppId") | ||
public AppNamespace batchDeleteByAppId( | ||
@ApolloAuditLogDataInfluence | ||
@ApolloAuditLogDataInfluenceTable(tableName="AppNamespace") | ||
@ApolloAuditLogDataInfluenceTableField(fieldName="AppId") String appId) { | ||
// ... | ||
} | ||
``` | ||
|
||
This will generate a special data influence. It means that all entities matching the input parameter value have been affected. | ||
|
||
## How to verify the audit-log work | ||
|
||
### check-by-UI | ||
|
||
The entrance of audit log UI is in Admin Tools. | ||
|
||
Then, we can check if the AuditLogs are created properly by searching or just find in table below. | ||
|
||
Then, check in the trace detail page. | ||
|
||
We can check if the relationship between AuditLogs are correct and the DataInfluences caused by certain AuditLog is logically established. | ||
|
||
In the rightmost column, we can view the historical operation records of the specified field's value. Null means being deleted~ | ||
|
||
### check-by-database | ||
|
||
The databases are in ApolloPortalDB, the table `AuditLog` and `AuditLogDataInfluence`. | ||
|
||
We can verify if the parent/followsfrom relationships are in line with our expectations. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!-- | ||
~ Copyright 2023 Apollo Authors | ||
~ | ||
~ Licensed 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. | ||
~ | ||
--> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<parent> | ||
<artifactId>apollo-audit</artifactId> | ||
<groupId>com.ctrip.framework.apollo</groupId> | ||
<version>${revision}</version> | ||
</parent> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<artifactId>apollo-audit-annotation</artifactId> | ||
<version>${revision}</version> | ||
|
||
</project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* | ||
* Copyright 2023 Apollo Authors | ||
* | ||
* Licensed 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 com.ctrip.framework.apollo.audit.annotation; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
/** | ||
* Mark which method should be audited, add to controller or service's method. | ||
* <p></p> | ||
* Define the attributes of the operation for persisting and querying. When adding to controller's | ||
* methods, suggested that don't set name, and it will automatically be set to request's url. | ||
* <p></p> | ||
* Example usage: | ||
* <pre> | ||
* {@code | ||
* @ApolloAuditLog(type=OpType.CREATE,name="App.create") | ||
* public App create() { | ||
* // ... | ||
* } | ||
* } | ||
* </pre> | ||
* | ||
* @author luke0125 | ||
* @since 2.2.0 | ||
*/ | ||
@Target(ElementType.METHOD) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
public @interface ApolloAuditLog { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. need javadoc in all annotation and api |
||
|
||
/** | ||
* Define the type of operation. | ||
* | ||
* @return operation type | ||
*/ | ||
OpType type(); | ||
|
||
/** | ||
* Define the name of operation. The requested URL will be taken by default if no specific name is | ||
* specified. | ||
* | ||
* @return operation name | ||
*/ | ||
String name() default ""; | ||
|
||
/** | ||
* Define the description of operation. Default is "no description". | ||
* | ||
* @return operation description | ||
*/ | ||
String description() default "no description"; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
* Copyright 2023 Apollo Authors | ||
* | ||
* Licensed 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 com.ctrip.framework.apollo.audit.annotation; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
/** | ||
* Combine with {@link ApolloAuditLog}, mark which method's parameter is audit log's data change. | ||
* <p></p> | ||
* Example usage: | ||
* <pre> | ||
* {@code | ||
* @ApolloAuditLog(type=OpType.DELETE,name="AppNamespace.batchDeleteByAppId") | ||
* public AppNamespace batchDeleteByAppId( | ||
* @ApolloAuditLogDataInfluence String appId) { | ||
* // ... | ||
* } | ||
* } | ||
* </pre> | ||
* | ||
* @author luke0125 | ||
* @since 2.2.0 | ||
*/ | ||
@Target(ElementType.PARAMETER) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
public @interface ApolloAuditLogDataInfluence { | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may use 5W1H to describe it.