diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 19bbec2de9..3e315153cb 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1529,6 +1529,12 @@ admin/views/moderators.vue:
     added: "モデレーターを登録しました"
     remove: "解除"
     removed: "モデレーター登録を解除しました"
+  logs:
+    title: "ログ"
+    moderator: "モデレーター"
+    type: "操作"
+    at: "日時"
+    info: "情報"
 
 admin/views/emoji.vue:
   add-emoji:
diff --git a/migration/1562869971568-ModerationLog.ts b/migration/1562869971568-ModerationLog.ts
new file mode 100644
index 0000000000..b37f38ee5d
--- /dev/null
+++ b/migration/1562869971568-ModerationLog.ts
@@ -0,0 +1,17 @@
+import {MigrationInterface, QueryRunner} from "typeorm";
+
+export class ModerationLog1562869971568 implements MigrationInterface {
+
+    public async up(queryRunner: QueryRunner): Promise<any> {
+        await queryRunner.query(`CREATE TABLE "moderation_log" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "type" character varying(128) NOT NULL, "info" jsonb NOT NULL, CONSTRAINT "PK_d0adca6ecfd068db83e4526cc26" PRIMARY KEY ("id"))`);
+        await queryRunner.query(`CREATE INDEX "IDX_a08ad074601d204e0f69da9a95" ON "moderation_log" ("userId") `);
+        await queryRunner.query(`ALTER TABLE "moderation_log" ADD CONSTRAINT "FK_a08ad074601d204e0f69da9a954" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
+    }
+
+    public async down(queryRunner: QueryRunner): Promise<any> {
+        await queryRunner.query(`ALTER TABLE "moderation_log" DROP CONSTRAINT "FK_a08ad074601d204e0f69da9a954"`);
+        await queryRunner.query(`DROP INDEX "IDX_a08ad074601d204e0f69da9a95"`);
+        await queryRunner.query(`DROP TABLE "moderation_log"`);
+    }
+
+}
diff --git a/src/client/app/admin/views/moderators.vue b/src/client/app/admin/views/moderators.vue
index bf7d951fc7..8ceab02d97 100644
--- a/src/client/app/admin/views/moderators.vue
+++ b/src/client/app/admin/views/moderators.vue
@@ -12,6 +12,31 @@
 			</ui-horizon-group>
 		</section>
 	</ui-card>
+
+	<ui-card>
+		<template #title>{{ $t('logs.title') }}</template>
+		<section class="fit-top">
+			<sequential-entrance animation="entranceFromTop" delay="25">
+				<div v-for="log in logs" :key="log.id" class="">
+					<ui-horizon-group inputs>
+						<ui-input :value="log.user | acct" type="text" readonly>
+							<span>{{ $t('logs.moderator') }}</span>
+						</ui-input>
+						<ui-input :value="log.type" type="text" readonly>
+							<span>{{ $t('logs.type') }}</span>
+						</ui-input>
+						<ui-input :value="log.createdAt | date" type="text" readonly>
+							<span>{{ $t('logs.at') }}</span>
+						</ui-input>
+					</ui-horizon-group>
+					<ui-textarea :value="JSON.stringify(log.info, null, 4)" readonly>
+						<span>{{ $t('logs.info') }}</span>
+					</ui-textarea>
+				</div>
+			</sequential-entrance>
+			<ui-button v-if="existMoreLogs" @click="fetchLogs">{{ $t('@.load-more') }}</ui-button>
+		</section>
+	</ui-card>
 </div>
 </template>
 
@@ -26,10 +51,17 @@ export default Vue.extend({
 	data() {
 		return {
 			username: '',
-			changing: false
+			changing: false,
+			logs: [],
+			untilLogId: null,
+			existMoreLogs: false
 		};
 	},
 
+	created() {
+		this.fetchLogs();
+	},
+
 	methods: {
 		async add() {
 			this.changing = true;
@@ -74,6 +106,22 @@ export default Vue.extend({
 
 			this.changing = false;
 		},
+
+		fetchLogs() {
+			this.$root.api('admin/show-moderation-logs', {
+				untilId: this.untilId,
+				limit: 10 + 1
+			}).then(logs => {
+				if (logs.length == 10 + 1) {
+					logs.pop();
+					this.existMoreLogs = true;
+				} else {
+					this.existMoreLogs = false;
+				}
+				this.logs = this.logs.concat(logs);
+				this.untilLogId = this.logs[this.logs.length - 1].id;
+			});
+		},
 	}
 });
 </script>
diff --git a/src/db/postgre.ts b/src/db/postgre.ts
index 638d5720b7..16cfbd2b2f 100644
--- a/src/db/postgre.ts
+++ b/src/db/postgre.ts
@@ -47,6 +47,7 @@ import { UserSecurityKey } from '../models/entities/user-security-key';
 import { AttestationChallenge } from '../models/entities/attestation-challenge';
 import { Page } from '../models/entities/page';
 import { PageLike } from '../models/entities/page-like';
+import { ModerationLog } from '../models/entities/moderation-log';
 
 const sqlLogger = dbLogger.createSubLogger('sql', 'white', false);
 
@@ -124,6 +125,7 @@ export const entities = [
 	RegistrationTicket,
 	MessagingMessage,
 	Signin,
+	ModerationLog,
 	ReversiGame,
 	ReversiMatching,
 	...charts as any
diff --git a/src/models/entities/moderation-log.ts b/src/models/entities/moderation-log.ts
new file mode 100644
index 0000000000..33d3d683ae
--- /dev/null
+++ b/src/models/entities/moderation-log.ts
@@ -0,0 +1,32 @@
+import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm';
+import { User } from './user';
+import { id } from '../id';
+
+@Entity()
+export class ModerationLog {
+	@PrimaryColumn(id())
+	public id: string;
+
+	@Column('timestamp with time zone', {
+		comment: 'The created date of the ModerationLog.'
+	})
+	public createdAt: Date;
+
+	@Index()
+	@Column(id())
+	public userId: User['id'];
+
+	@ManyToOne(type => User, {
+		onDelete: 'CASCADE'
+	})
+	@JoinColumn()
+	public user: User | null;
+
+	@Column('varchar', {
+		length: 128,
+	})
+	public type: string;
+
+	@Column('jsonb')
+	public info: Record<string, any>;
+}
diff --git a/src/models/index.ts b/src/models/index.ts
index 888fd53f36..388bdc8f6f 100644
--- a/src/models/index.ts
+++ b/src/models/index.ts
@@ -42,6 +42,7 @@ import { UserSecurityKey } from './entities/user-security-key';
 import { HashtagRepository } from './repositories/hashtag';
 import { PageRepository } from './repositories/page';
 import { PageLikeRepository } from './repositories/page-like';
+import { ModerationLogRepository } from './repositories/moderation-logs';
 
 export const Apps = getCustomRepository(AppRepository);
 export const Notes = getCustomRepository(NoteRepository);
@@ -86,3 +87,4 @@ export const ReversiMatchings = getCustomRepository(ReversiMatchingRepository);
 export const Logs = getRepository(Log);
 export const Pages = getCustomRepository(PageRepository);
 export const PageLikes = getCustomRepository(PageLikeRepository);
+export const ModerationLogs = getCustomRepository(ModerationLogRepository);
diff --git a/src/models/repositories/moderation-logs.ts b/src/models/repositories/moderation-logs.ts
new file mode 100644
index 0000000000..d6e04795bb
--- /dev/null
+++ b/src/models/repositories/moderation-logs.ts
@@ -0,0 +1,31 @@
+import { EntityRepository, Repository } from 'typeorm';
+import { Users } from '..';
+import { ModerationLog } from '../entities/moderation-log';
+import { ensure } from '../../prelude/ensure';
+import { awaitAll } from '../../prelude/await-all';
+
+@EntityRepository(ModerationLog)
+export class ModerationLogRepository extends Repository<ModerationLog> {
+	public async pack(
+		src: ModerationLog['id'] | ModerationLog,
+	) {
+		const log = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
+
+		return await awaitAll({
+			id: log.id,
+			createdAt: log.createdAt,
+			type: log.type,
+			info: log.info,
+			userId: log.userId,
+			user: Users.pack(log.user || log.userId, null, {
+				detail: true
+			}),
+		});
+	}
+
+	public packMany(
+		reports: any[],
+	) {
+		return Promise.all(reports.map(x => this.pack(x)));
+	}
+}
diff --git a/src/server/api/endpoints/admin/emoji/add.ts b/src/server/api/endpoints/admin/emoji/add.ts
index 5ba00afde8..8c21b1c73e 100644
--- a/src/server/api/endpoints/admin/emoji/add.ts
+++ b/src/server/api/endpoints/admin/emoji/add.ts
@@ -4,6 +4,7 @@ import { detectUrlMine } from '../../../../../misc/detect-url-mine';
 import { Emojis } from '../../../../../models';
 import { genId } from '../../../../../misc/gen-id';
 import { getConnection } from 'typeorm';
+import { insertModerationLog } from '../../../../../services/insert-moderation-log';
 
 export const meta = {
 	desc: {
@@ -31,7 +32,7 @@ export const meta = {
 	}
 };
 
-export default define(meta, async (ps) => {
+export default define(meta, async (ps, me) => {
 	const type = await detectUrlMine(ps.url);
 
 	const emoji = await Emojis.save({
@@ -46,6 +47,10 @@ export default define(meta, async (ps) => {
 
 	await getConnection().queryResultCache!.remove(['meta_emojis']);
 
+	insertModerationLog(me, 'addEmoji', {
+		emojiId: emoji.id
+	});
+
 	return {
 		id: emoji.id
 	};
diff --git a/src/server/api/endpoints/admin/emoji/remove.ts b/src/server/api/endpoints/admin/emoji/remove.ts
index 3ebf933bc6..92c5f5f8c6 100644
--- a/src/server/api/endpoints/admin/emoji/remove.ts
+++ b/src/server/api/endpoints/admin/emoji/remove.ts
@@ -3,6 +3,7 @@ import define from '../../../define';
 import { ID } from '../../../../../misc/cafy-id';
 import { Emojis } from '../../../../../models';
 import { getConnection } from 'typeorm';
+import { insertModerationLog } from '../../../../../services/insert-moderation-log';
 
 export const meta = {
 	desc: {
@@ -21,7 +22,7 @@ export const meta = {
 	}
 };
 
-export default define(meta, async (ps) => {
+export default define(meta, async (ps, me) => {
 	const emoji = await Emojis.findOne(ps.id);
 
 	if (emoji == null) throw new Error('emoji not found');
@@ -29,4 +30,8 @@ export default define(meta, async (ps) => {
 	await Emojis.delete(emoji.id);
 
 	await getConnection().queryResultCache!.remove(['meta_emojis']);
+
+	insertModerationLog(me, 'removeEmoji', {
+		emoji: emoji
+	});
 });
diff --git a/src/server/api/endpoints/admin/queue/clear.ts b/src/server/api/endpoints/admin/queue/clear.ts
index f0fd00f1ad..03c1ae8463 100644
--- a/src/server/api/endpoints/admin/queue/clear.ts
+++ b/src/server/api/endpoints/admin/queue/clear.ts
@@ -1,5 +1,6 @@
 import define from '../../../define';
 import { destroy } from '../../../../../queue';
+import { insertModerationLog } from '../../../../../services/insert-moderation-log';
 
 export const meta = {
 	tags: ['admin'],
@@ -10,8 +11,8 @@ export const meta = {
 	params: {}
 };
 
-export default define(meta, async (ps) => {
+export default define(meta, async (ps, me) => {
 	destroy();
 
-	return;
+	insertModerationLog(me, 'clearQueue');
 });
diff --git a/src/server/api/endpoints/admin/show-moderation-logs.ts b/src/server/api/endpoints/admin/show-moderation-logs.ts
new file mode 100644
index 0000000000..bc67b3e55b
--- /dev/null
+++ b/src/server/api/endpoints/admin/show-moderation-logs.ts
@@ -0,0 +1,35 @@
+import $ from 'cafy';
+import { ID } from '../../../../misc/cafy-id';
+import define from '../../define';
+import { ModerationLogs } from '../../../../models';
+import { makePaginationQuery } from '../../common/make-pagination-query';
+
+export const meta = {
+	tags: ['admin'],
+
+	requireCredential: true,
+	requireModerator: true,
+
+	params: {
+		limit: {
+			validator: $.optional.num.range(1, 100),
+			default: 10
+		},
+
+		sinceId: {
+			validator: $.optional.type(ID),
+		},
+
+		untilId: {
+			validator: $.optional.type(ID),
+		},
+	}
+};
+
+export default define(meta, async (ps) => {
+	const query = makePaginationQuery(ModerationLogs.createQueryBuilder('report'), ps.sinceId, ps.untilId);
+
+	const reports = await query.take(ps.limit!).getMany();
+
+	return await ModerationLogs.packMany(reports);
+});
diff --git a/src/server/api/endpoints/admin/silence-user.ts b/src/server/api/endpoints/admin/silence-user.ts
index 83aa88012a..8cc84aa1cc 100644
--- a/src/server/api/endpoints/admin/silence-user.ts
+++ b/src/server/api/endpoints/admin/silence-user.ts
@@ -2,6 +2,7 @@ import $ from 'cafy';
 import { ID } from '../../../../misc/cafy-id';
 import define from '../../define';
 import { Users } from '../../../../models';
+import { insertModerationLog } from '../../../../services/insert-moderation-log';
 
 export const meta = {
 	desc: {
@@ -25,7 +26,7 @@ export const meta = {
 	}
 };
 
-export default define(meta, async (ps) => {
+export default define(meta, async (ps, me) => {
 	const user = await Users.findOne(ps.userId as string);
 
 	if (user == null) {
@@ -39,4 +40,8 @@ export default define(meta, async (ps) => {
 	await Users.update(user.id, {
 		isSilenced: true
 	});
+
+	insertModerationLog(me, 'silence', {
+		targetId: user.id,
+	});
 });
diff --git a/src/server/api/endpoints/admin/suspend-user.ts b/src/server/api/endpoints/admin/suspend-user.ts
index fa4d378708..09fdbb070e 100644
--- a/src/server/api/endpoints/admin/suspend-user.ts
+++ b/src/server/api/endpoints/admin/suspend-user.ts
@@ -4,6 +4,7 @@ import define from '../../define';
 import deleteFollowing from '../../../../services/following/delete';
 import { Users, Followings } from '../../../../models';
 import { User } from '../../../../models/entities/user';
+import { insertModerationLog } from '../../../../services/insert-moderation-log';
 
 export const meta = {
 	desc: {
@@ -27,7 +28,7 @@ export const meta = {
 	}
 };
 
-export default define(meta, async (ps) => {
+export default define(meta, async (ps, me) => {
 	const user = await Users.findOne(ps.userId as string);
 
 	if (user == null) {
@@ -46,6 +47,10 @@ export default define(meta, async (ps) => {
 		isSuspended: true
 	});
 
+	insertModerationLog(me, 'suspend', {
+		targetId: user.id,
+	});
+
 	unFollowAll(user);
 });
 
diff --git a/src/server/api/endpoints/admin/unsilence-user.ts b/src/server/api/endpoints/admin/unsilence-user.ts
index f9b173366b..607c9b699a 100644
--- a/src/server/api/endpoints/admin/unsilence-user.ts
+++ b/src/server/api/endpoints/admin/unsilence-user.ts
@@ -2,6 +2,7 @@ import $ from 'cafy';
 import { ID } from '../../../../misc/cafy-id';
 import define from '../../define';
 import { Users } from '../../../../models';
+import { insertModerationLog } from '../../../../services/insert-moderation-log';
 
 export const meta = {
 	desc: {
@@ -25,7 +26,7 @@ export const meta = {
 	}
 };
 
-export default define(meta, async (ps) => {
+export default define(meta, async (ps, me) => {
 	const user = await Users.findOne(ps.userId as string);
 
 	if (user == null) {
@@ -35,4 +36,8 @@ export default define(meta, async (ps) => {
 	await Users.update(user.id, {
 		isSilenced: false
 	});
+
+	insertModerationLog(me, 'unsilence', {
+		targetId: user.id,
+	});
 });
diff --git a/src/server/api/endpoints/admin/unsuspend-user.ts b/src/server/api/endpoints/admin/unsuspend-user.ts
index 08dae034d3..a1c80d3121 100644
--- a/src/server/api/endpoints/admin/unsuspend-user.ts
+++ b/src/server/api/endpoints/admin/unsuspend-user.ts
@@ -2,6 +2,7 @@ import $ from 'cafy';
 import { ID } from '../../../../misc/cafy-id';
 import define from '../../define';
 import { Users } from '../../../../models';
+import { insertModerationLog } from '../../../../services/insert-moderation-log';
 
 export const meta = {
 	desc: {
@@ -25,7 +26,7 @@ export const meta = {
 	}
 };
 
-export default define(meta, async (ps) => {
+export default define(meta, async (ps, me) => {
 	const user = await Users.findOne(ps.userId as string);
 
 	if (user == null) {
@@ -35,4 +36,8 @@ export default define(meta, async (ps) => {
 	await Users.update(user.id, {
 		isSuspended: false
 	});
+
+	insertModerationLog(me, 'unsuspend', {
+		targetId: user.id,
+	});
 });
diff --git a/src/server/api/endpoints/admin/update-meta.ts b/src/server/api/endpoints/admin/update-meta.ts
index 8e98d203ff..834faa42b9 100644
--- a/src/server/api/endpoints/admin/update-meta.ts
+++ b/src/server/api/endpoints/admin/update-meta.ts
@@ -2,6 +2,7 @@ import $ from 'cafy';
 import define from '../../define';
 import { getConnection } from 'typeorm';
 import { Meta } from '../../../../models/entities/meta';
+import { insertModerationLog } from '../../../../services/insert-moderation-log';
 
 export const meta = {
 	desc: {
@@ -401,7 +402,7 @@ export const meta = {
 	}
 };
 
-export default define(meta, async (ps) => {
+export default define(meta, async (ps, me) => {
 	const set = {} as Partial<Meta>;
 
 	if (ps.announcements) {
@@ -653,4 +654,6 @@ export default define(meta, async (ps) => {
 			await transactionalEntityManager.save(Meta, set);
 		}
 	});
+
+	insertModerationLog(me, 'updateMeta');
 });
diff --git a/src/server/api/endpoints/admin/vacuum.ts b/src/server/api/endpoints/admin/vacuum.ts
index 6990706282..4921e228e5 100644
--- a/src/server/api/endpoints/admin/vacuum.ts
+++ b/src/server/api/endpoints/admin/vacuum.ts
@@ -1,6 +1,7 @@
 import $ from 'cafy';
 import define from '../../define';
 import { getConnection } from 'typeorm';
+import { insertModerationLog } from '../../../../services/insert-moderation-log';
 
 export const meta = {
 	tags: ['admin'],
@@ -18,7 +19,7 @@ export const meta = {
 	}
 };
 
-export default define(meta, async (ps) => {
+export default define(meta, async (ps, me) => {
 	const params: string[] = [];
 
 	if (ps.full) {
@@ -30,4 +31,6 @@ export default define(meta, async (ps) => {
 	}
 
 	getConnection().query('VACUUM ' + params.join(' '));
+
+	insertModerationLog(me, 'vacuum', ps);
 });
diff --git a/src/services/insert-moderation-log.ts b/src/services/insert-moderation-log.ts
new file mode 100644
index 0000000000..33dab97259
--- /dev/null
+++ b/src/services/insert-moderation-log.ts
@@ -0,0 +1,13 @@
+import { ILocalUser } from '../models/entities/user';
+import { ModerationLogs } from '../models';
+import { genId } from '../misc/gen-id';
+
+export async function insertModerationLog(moderator: ILocalUser, type: string, info?: Record<string, any>) {
+	await ModerationLogs.save({
+		id: genId(),
+		createdAt: new Date(),
+		userId: moderator.id,
+		type: type,
+		info: info || {}
+	});
+}