Guide to the Audit Log plugin, including installation, log table setup, resource wiring, and tracking of admin changes, custom actions, and client metadata.
AuditLog plugin allows to log all changes in the resources done from the admin panel. It will allow you to figure out who and when made changes in the data. Requires separate table in the database to store logs.
pnpm add @adminforth/audit-log --saveCreate auditLogs.ts in resources folder:
import AuditLogPlugin from '@adminforth/audit-log';
import { AdminForthDataTypes } from 'adminforth'Getting Started will be used as base for this example.
For the first, to track records changes, we need to set up the database and table with certain fields inside where tracked data will be stored.
First of all you should create this table in your own database ./schema.prisma:
model audit_logs {
id String @id
created_at DateTime /// timestamp of applied change
resource_id String /// identifier of resource where change were applied
user_id String /// identifier of user who made the changes
action String /// type of change (create, edit, delete)
diff String? /// delta betwen before/after versions
record_id String? /// identifier of record that been changed
}And prisma migrate:
pnpm makemigration --name add-audit-logs ; pnpm migrate:localAlso to make this code start
Logger sets up for all the resources by default. But you can exclude unwanted resources with option "excludeResourceIds". In this example, we'll exclude resource "adminuser" from logging.
Also, it excludes itself to avoid infinte logging loop.
Add this code in auditLogs.ts:
import AuditLogPlugin from "@adminforth/audit-log/index.js";
import { AdminForthDataTypes } from "adminforth";
import { randomUUID } from "crypto";
export default {
dataSource: 'maindb',
table: 'audit_logs',
columns: [
{ name: 'id', primaryKey: true, required: false, fillOnCreate: ({initialRecord}: any) => randomUUID(),
showIn: {
list: false,
edit: false,
create: false,
filter: false,
} },
{ name: 'created_at', required: false },
{ name: 'resource_id', required: false },
{ name: 'user_id', required: false,
foreignResource: {
resourceId: 'adminuser',
} },
{ name: 'action', required: false },
{ name: 'diff', required: false, type: AdminForthDataTypes.JSON, showIn: {
list: false,
edit: false,
create: false,
filter: false,
} },
{ name: 'record_id', required: false },
],
options: {
allowedActions: {
edit: false,
delete: false,
create: false
}
},
plugins: [
new AuditLogPlugin({
// if you want to exclude some resources from logging
//excludeResourceIds: ['adminuser'],
resourceColumns: {
resourceIdColumnName: 'resource_id',
resourceActionColumnName: 'action',
resourceDataColumnName: 'diff',
resourceUserIdColumnName: 'user_id',
resourceRecordIdColumnName: 'record_id',
resourceCreatedColumnName: 'created_at'
}
}),
],
}Then you need to import ./resources/auditLogs:
//diff-add
import auditLogsResource from "./resources/auditLogs"
... new AdminForth({
dataSources: [...],
...
resources: [
apartmentsResource,
usersResource,
//diff-add
auditLogsResource
],
...
]Also, we need to add it to menu:
menu: [
...
//diff-add
{
//diff-add
label: 'Audit Logs',
//diff-add
icon: 'flowbite:search-outline',
//diff-add
resourceId: 'audit_logs',
//diff-add
}
]That's it! Now you can see the logs in the table
Audit log is able to catch only standard actions like create, update, delete or custom bulk actions.
If you have a custom, self coded actions in your API, you can log them by calling logCustomAction method of AuditLogPlugin instance:
import type { IAdminUserExpressRequest, ITranslateExpressRequest } from 'adminforth';
import express from 'express';
....
app.get(`${ADMIN_BASE_URL}/api/dashboard/`,
admin.express.authorize(
async (req: IAdminUserExpressRequest, res: express.Response) => {
admin.getPluginByClassName<AuditLogPlugin>('AuditLogPlugin').logCustomAction({
resourceId: 'aparts',
recordId: null, // recordId can be null if not applicable
actionId: 'visitedDashboard', // any random string you want to useto identify this action
oldData: null, // old data, can be null if not applicable
data: { dashboard: 'main' }, // new data or any data you want to log
user: req.adminUser,
headers: req.headers //required if you want log client ip
})
....Audit log can also log the client's IP address if needed.
First, you need to migrate the audit_logs table in ./schema.prisma:
model audit_logs {
id String @id
created_at DateTime /// timestamp of applied change
resource_id String /// identifier of resource where change were applied
user_id String /// identifier of user who made the changes
action String /// type of change (create, edit, delete)
diff String? /// delta betwen before/after versions
record_id String? /// identifier of record that been changed
//diff-add
ip_address String? /// client ip address
}And prisma migrate:
pnpm makemigration --name add-ip-address-to-audit-logs ; pnpm migrate:localAlso, update the resource configuration in ./resources/auditLogs.ts:
export default {
dataSource: 'maindb',
table: 'audit_logs',
columns: [
...
{ name: 'action', required: false },
{ name: 'diff', required: false, type: AdminForthDataTypes.JSON, showIn: {
list: false,
edit: false,
create: false,
filter: false,
} },
{ name: 'record_id', required: false },
//diff-add
{ name: 'ip_address', required: false },
],
...
plugins: [
new AuditLogPlugin({
resourceColumns: {
resourceIdColumnName: 'resource_id',
resourceActionColumnName: 'action',
resourceDataColumnName: 'diff',
resourceUserIdColumnName: 'user_id',
resourceRecordIdColumnName: 'record_id',
resourceCreatedColumnName: 'created_at'
//diff-add
resourceIpColumnName: "ip_address",
}
}),
],
}Audit log can also log the client's country if needed.
First, you need to migrate the audit_logs table in ./schema.prisma:
model audit_logs {
id String @id
created_at DateTime /// timestamp of applied change
resource_id String /// identifier of resource where change were applied
user_id String /// identifier of user who made the changes
action String /// type of change (create, edit, delete)
diff String? /// delta betwen before/after versions
record_id String? /// identifier of record that been changed
ip_address String? /// client ip address
//diff-add
country String? /// client country
//diff-add
@@index([ip_address]) /// index for fast lookups by IP
}And prisma migrate:
pnpm makemigration --name add-ip-address-to-audit-logs ; pnpm migrate:localUpdate the resource configuration in ./resources/auditLogs.ts:
export default {
dataSource: 'maindb',
table: 'audit_logs',
columns: [
...
{ name: 'action', required: false },
{ name: 'diff', required: false, type: AdminForthDataTypes.JSON, showIn: {
list: false,
edit: false,
create: false,
filter: false,
} },
{ name: 'record_id', required: false },
{ name: 'ip_address', required: false },
//diff-add
{
//diff-add
name: "country",
//diff-add
required: false,
//diff-add
components: {
//diff-add
list: '@/renderers/CountryFlag.vue'
//diff-add
show: '@/renderers/CountryFlag.vue'
//diff-add
},
//diff-add
},
],
...
plugins: [
new AuditLogPlugin({
resourceColumns: {
resourceIdColumnName: 'resource_id',
resourceActionColumnName: 'action',
resourceDataColumnName: 'diff',
resourceUserIdColumnName: 'user_id',
resourceRecordIdColumnName: 'record_id',
resourceCreatedColumnName: 'created_at'
resourceIpColumnName: "ip_address",
//diff-add
resourceCountryColumnName: "country",
}
}),
],
}If your deployed app has header with user country in ISO 3166-1 alpha-2 format, you can specify this header, so country will be taken from it:
plugins: [
new AuditLogPlugin({
//diff-add
isoCountryCodeRequestHeader: 'CF-IPCountry',
resourceColumns: {
resourceIdColumnName: 'resource_id',
resourceActionColumnName: 'action',
resourceDataColumnName: 'diff',
resourceUserIdColumnName: 'user_id',
resourceRecordIdColumnName: 'record_id',
resourceCreatedColumnName: 'created_at'
resourceIpColumnName: "ip_address",
resourceCountryColumnName: "country",
}
}),
],