diff --git a/src/clientfactory.ts b/src/clientfactory.ts
index b2a5baeb9a1886d40201248f3a8323ad884b8815..f43ca851b81036dca8dec080c19f345bf98ebeba 100644
--- a/src/clientfactory.ts
+++ b/src/clientfactory.ts
@@ -123,17 +123,17 @@ export class DiscordClientFactory {
     }
 
     public bindMetricsToChannel(channel: TextChannel) {
-        // tslint:disable-next-line:no-any
+        // eslint-disable-next-line @typescript-eslint/no-explicit-any
         const flexChan = channel as any;
         if (flexChan._xmet_send !== undefined) {
             return;
         }
         // Prefix the real functions with _xmet_
+        // eslint-disable-next-line @typescript-eslint/camelcase
         flexChan._xmet_send = channel.send;
-        // tslint:disable-next-line:only-arrow-functions
-        channel.send = function() {
+        channel.send = (...rest) => {
             MetricPeg.get.remoteCall("channel.send");
-            return flexChan._xmet_send.apply(channel, arguments);
+            return flexChan._xmet_send.apply(channel, rest);
         };
     }
 }
diff --git a/src/config.ts b/src/config.ts
index 51b6c2ae4c8ba12ed4c5d760044620768d2d73c3..2706ba201c1d3b8600523183838eabbf561765eb 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -35,7 +35,7 @@ export class DiscordBridgeConfig {
      * @param newConfig Config keys
      * @param configLayer Private parameter
      */
-    // tslint:disable-next-line no-any
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
     public applyConfig(newConfig: {[key: string]: any}, configLayer: {[key: string]: any} = this) {
           Object.keys(newConfig).forEach((key) => {
             if (configLayer[key] instanceof Object && !(configLayer[key] instanceof Array)) {
@@ -53,10 +53,10 @@ export class DiscordBridgeConfig {
      * @param configLayer private parameter: current layer of configuration to alter recursively
      */
     public applyEnvironmentOverrides(
-        // tslint:disable-next-line no-any
+        // eslint-disable-next-line @typescript-eslint/no-explicit-any
         environment: {[key: string]: any},
         path: string[] = [ENV_PREFIX],
-        // tslint:disable-next-line no-any
+        // eslint-disable-next-line @typescript-eslint/no-explicit-any
         configLayer: {[key: string]: any} = this,
     ) {
         Object.keys(configLayer).forEach((key) => {
diff --git a/src/db/dbdataevent.ts b/src/db/dbdataevent.ts
index 46c8a9387548a5fde822980ba157307c0985d035..30db142bebd5fd69dfd3e0b295dd748fc22b9f19 100644
--- a/src/db/dbdataevent.ts
+++ b/src/db/dbdataevent.ts
@@ -24,7 +24,7 @@ export class DbEvent implements IDbDataMany {
     public GuildId: string;
     public ChannelId: string;
     public Result: boolean;
-    // tslint:disable-next-line no-any
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
     private rows: any[];
 
     get ResultCount(): number {
@@ -33,7 +33,7 @@ export class DbEvent implements IDbDataMany {
 
     public async RunQuery(store: DiscordStore, params: ISqlCommandParameters): Promise<void> {
         this.rows = [];
-        // tslint:disable-next-line no-any
+        // eslint-disable-next-line @typescript-eslint/no-explicit-any
         let rowsM: any[] | null = null;
         if (params.matrix_id) {
             rowsM = await store.db.All(`
@@ -64,7 +64,7 @@ export class DbEvent implements IDbDataMany {
                     WHERE msg_id = $id`, {
                         id: rowM.discord_id,
             })) {
-                // tslint:disable-next-line no-any
+                // eslint-disable-next-line @typescript-eslint/no-explicit-any
                 const insertRow: any = Object.assign({}, row);
                 insertRow.guild_id = rowD.guild_id;
                 insertRow.channel_id = rowD.channel_id;
diff --git a/src/db/dbdatainterface.ts b/src/db/dbdatainterface.ts
index 043bec08ba887e8b927a3b35eea6a7be7cc110a7..2a66a6b3894faf0ad2a6abbae4b18118fddced01 100644
--- a/src/db/dbdatainterface.ts
+++ b/src/db/dbdatainterface.ts
@@ -18,7 +18,7 @@ import { DiscordStore } from "../store";
 
 export interface IDbData {
     Result: boolean;
-    // tslint:disable-next-line no-any
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
     RunQuery(store: DiscordStore, params: any): Promise<void|Error>;
     Insert(store: DiscordStore): Promise<void|Error>;
     Update(store: DiscordStore): Promise<void|Error>;
diff --git a/src/db/postgres.ts b/src/db/postgres.ts
index 0b41112e95378845c20e3d9d18a84705f5f6e549..26ebcaf5cb091665bfebe942d12c97aa4dd47713 100644
--- a/src/db/postgres.ts
+++ b/src/db/postgres.ts
@@ -30,7 +30,7 @@ export class Postgres implements IDatabaseConnector {
         });
     }
 
-    // tslint:disable-next-line no-any
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
     private db: pgPromise.IDatabase<any>;
     constructor(private connectionString: string) {
 
diff --git a/src/db/roomstore.ts b/src/db/roomstore.ts
index ed311a8ca450258f1aeb83fd2d7fb33ba37cc293..3e04cbf88dd5e378ce8d358d73a50709e200fe0c 100644
--- a/src/db/roomstore.ts
+++ b/src/db/roomstore.ts
@@ -173,7 +173,7 @@ export class DbRoomStore {
                     {remoteId},
                 );
                 if (row) {
-                    // tslint:disable-next-line no-any
+                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
                     remote = new RemoteStoreRoom(remoteId, row as any);
                 }
             }
@@ -209,7 +209,7 @@ export class DbRoomStore {
                     {rid: remoteId},
                 );
                 if (row) {
-                    // tslint:disable-next-line no-any
+                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
                     remote = new RemoteStoreRoom(remoteId, row as any);
                 }
             }
@@ -261,7 +261,7 @@ export class DbRoomStore {
         SELECT * FROM remote_room_data
         INNER JOIN room_entries ON remote_room_data.room_id = room_entries.remote_id
         WHERE ${whereClaues}`;
-        // tslint:disable-next-line no-any
+        // eslint-disable-next-line @typescript-eslint/no-explicit-any
         return (await this.db.All(sql, data as any)).map((row) => {
             const id = row.id as string;
             const matrixId = row.matrix_id;
@@ -269,7 +269,7 @@ export class DbRoomStore {
             return {
                 id,
                 matrix: matrixId ? new MatrixStoreRoom(matrixId as string) : null,
-                // tslint:disable-next-line no-any
+                // eslint-disable-next-line @typescript-eslint/no-explicit-any
                 remote: matrixId ? new RemoteStoreRoom(remoteId as string, row as any) : null,
             };
         });
@@ -338,7 +338,7 @@ export class DbRoomStore {
             `,
             {
                 id: room.roomId,
-                // tslint:disable-next-line no-any
+                // eslint-disable-next-line @typescript-eslint/no-explicit-any
                 ...data as any,
             });
             return;
@@ -372,7 +372,7 @@ export class DbRoomStore {
             await this.db.Run(`UPDATE remote_room_data SET ${setStatement} WHERE room_id = $id`,
             {
                 id: room.roomId,
-                // tslint:disable-next-line no-any
+                // eslint-disable-next-line @typescript-eslint/no-explicit-any
                 ...keysToUpdate as any,
             });
             log.verbose("Upserted room " + room.roomId);
diff --git a/src/discordas.ts b/src/discordas.ts
index b6c522553b8b86edd56e03b4a08f626981d3fc65..ad6c6cab94e8e5731770934648f884507d49be46 100644
--- a/src/discordas.ts
+++ b/src/discordas.ts
@@ -38,11 +38,12 @@ const commandOptions = [
     { name: "help", alias: "h", type: Boolean },
 ];
 
-function generateRegistration(opts, registrationPath)  {
+function generateRegistration(opts, registrationPath: string): void {
     if (!opts.url) {
         throw Error("'url' not given in command line opts, cannot generate registration file");
     }
     const reg = {
+        /* eslint-disable @typescript-eslint/camelcase */
         as_token: uuid(),
         hs_token: uuid(),
         id: "discord-bridge",
@@ -65,14 +66,15 @@ function generateRegistration(opts, registrationPath)  {
         rate_limited: false,
         sender_localpart: "_discord_bot",
         url: opts.url,
+        /* eslint-enable @typescript-eslint/camelcase */
     } as IAppserviceRegistration;
     fs.writeFileSync(registrationPath, yaml.safeDump(reg));
 }
 
-function setupLogging() {
+function setupLogging(): void {
     const logMap = new Map<string, Log>();
-    // tslint:disable-next-line:no-any
-    const logFunc = (level: string, module: string, args: any[]) => {
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
+    const logFunc = (level: string, module: string, args: any[]): void => {
         if (!Array.isArray(args)) {
             args = [args];
         }
@@ -80,7 +82,7 @@ function setupLogging() {
             // Spammy logs begon
             return;
         }
-        const mod = "bot-sdk" + module;
+        const mod = `bot-sdk${module}`;
         let logger = logMap.get(mod);
         if (!logger) {
             logger = new Log(mod);
@@ -90,18 +92,18 @@ function setupLogging() {
     };
 
     LogService.setLogger({
-        // tslint:disable-next-line:no-any
+        // eslint-disable-next-line @typescript-eslint/no-explicit-any
         debug: (mod: string, args: any[]) => logFunc("silly", mod, args),
-        // tslint:disable-next-line:no-any
+        // eslint-disable-next-line @typescript-eslint/no-explicit-any
         error: (mod: string, args: any[]) => logFunc("error", mod, args),
-        // tslint:disable-next-line:no-any
+        // eslint-disable-next-line @typescript-eslint/no-explicit-any
         info: (mod: string, args: any[]) => logFunc("info", mod, args),
-        // tslint:disable-next-line:no-any
+        // eslint-disable-next-line @typescript-eslint/no-explicit-any
         warn: (mod: string, args: any[]) => logFunc("warn", mod, args),
     });
 }
 
-async function run() {
+async function run(): Promise<void> {
     const opts = cliArgs(commandOptions);
     if (opts.help) {
         /* tslint:disable:no-console */
@@ -176,7 +178,7 @@ async function run() {
     const roomhandler = discordbot.RoomHandler;
     const eventProcessor = discordbot.MxEventProcessor;
 
-    // tslint:disable-next-line:no-any
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
     appservice.on("query.room", async (roomAlias: string, createRoom: (opts: any) => Promise<void>) => {
         try {
             const createRoomOpts = await roomhandler.OnAliasQuery(roomAlias);
diff --git a/src/log.ts b/src/log.ts
index 0477d8a1af5e77d3e47289f56a034a6afc3248e3..c33c4395407ba5551578fe8bcf1570bdf6588870 100644
--- a/src/log.ts
+++ b/src/log.ts
@@ -24,21 +24,21 @@ const FORMAT_FUNC = format.printf((info) => {
 });
 
 export class Log {
-    public static get level() {
+    public static get level(): string {
         return this.logger.level;
     }
 
-    public static set level(level) {
+    public static set level(level: string) {
         this.logger.level = level;
     }
 
-    public static Configure(config: DiscordBridgeConfigLogging) {
+    public static Configure(config: DiscordBridgeConfigLogging): void {
         // Merge defaults.
         Log.config = Object.assign(new DiscordBridgeConfigLogging(), config);
         Log.setupLogger();
     }
 
-    public static ForceSilent() {
+    public static ForceSilent(): void {
         new Log("Log").warn("Log set to silent");
         Log.logger.silent = true;
     }
@@ -46,7 +46,7 @@ export class Log {
     private static config: DiscordBridgeConfigLogging;
     private static logger: Logger;
 
-    private static setupLogger() {
+    private static setupLogger(): void {
         if (Log.logger) {
             Log.logger.close();
         }
@@ -92,41 +92,40 @@ export class Log {
             maxSize: config.maxSize,
         };
 
-        // tslint:disable-next-line no-any
+        // eslint-disable-next-line @typescript-eslint/no-explicit-any
         return new (transports as any).DailyRotateFile(opts);
     }
 
-    public warning = this.warn;
-
     constructor(private module: string) { }
 
-    // tslint:disable-next-line no-any
-    public error(...msg: any[]) {
+    public error(...msg: unknown[]): void {
         this.log("error", msg);
     }
 
-    // tslint:disable-next-line no-any
-    public warn(...msg: any[]) {
+    public warn(...msg: unknown[]): void {
         this.log("warn", msg);
     }
 
-    // tslint:disable-next-line no-any
-    public info(...msg: any[]) {
+    public warning(...msg: unknown[]): void {
+        this.warn(...msg);
+    }
+
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
+    public info(...msg: unknown[]): void {
         this.log("info", msg);
     }
 
-    // tslint:disable-next-line no-any
-    public verbose(...msg: any[]) {
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
+    public verbose(...msg: unknown[]): void {
         this.log("verbose", msg);
     }
 
-    // tslint:disable-next-line no-any
-    public silly(...msg: any[]) {
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
+    public silly(...msg: unknown[]): void {
         this.log("silly", msg);
     }
 
-    // tslint:disable-next-line no-any
-    private log(level: string, msg: any[]) {
+    private log(level: string, msg: unknown[]): void {
         if (!Log.logger) {
             // We've not configured the logger yet, so create a basic one.
             Log.config = new DiscordBridgeConfigLogging();
diff --git a/src/matrixcommandhandler.ts b/src/matrixcommandhandler.ts
index 61cedf68afbacd7e0efe0a6dd399e37456538f5e..2de594db08ba0519d1ae8433ff39333b17fc9976 100644
--- a/src/matrixcommandhandler.ts
+++ b/src/matrixcommandhandler.ts
@@ -59,7 +59,7 @@ export class MatrixCommandHandler {
         const actions: ICommandActions = {
             bridge: {
                 description: "Bridges this room to a Discord channel",
-                // tslint:disable prefer-template
+                /* eslint-disable prefer-template */
                 help: "How to bridge a Discord guild:\n" +
                     "1. Invite the bot to your Discord guild using this link: " + Util.GetBotLink(this.config) + "\n" +
                     "2. Invite me to the matrix room you'd like to bridge\n" +
@@ -69,7 +69,7 @@ export class MatrixCommandHandler {
                     "   Note: The Guild ID and Channel ID can be retrieved from the URL in your web browser.\n" +
                     "   The URL is formatted as https://discordapp.com/channels/GUILD_ID/CHANNEL_ID\n" +
                     "5. Enjoy your new bridge!",
-                // tslint:enable prefer-template
+                /* eslint-enable prefer-template */
                 params: ["guildId", "channelId"],
                 permission: {
                     cat: "events",
@@ -134,7 +134,7 @@ export class MatrixCommandHandler {
                         await this.provisioner.UnbridgeChannel(res.channel, event.room_id);
                         return "This room has been unbridged";
                     } catch (err) {
-                        log.error("Error while unbridging room " + event.room_id);
+                        log.error(`Error while unbridging room ${event.room_id}`);
                         log.error(err);
                         return "There was an error unbridging this room. " +
                             "Please try again later or contact the bridge operator.";
diff --git a/src/matrixroomhandler.ts b/src/matrixroomhandler.ts
index 5a7c4b8c1d7c417b91655c0cb4eddd5b43fe5956..ecbc30a65406e594f32a198ccd353c9bf9d1080b 100644
--- a/src/matrixroomhandler.ts
+++ b/src/matrixroomhandler.ts
@@ -65,13 +65,14 @@ export class MatrixRoomHandler {
                 this.tpGetProtocol(protocol)
                     .then(cb)
                     .catch((err) => log.warn("Failed to get protocol", err));
-        });
+            }
+        );
 
-        // tslint:disable-next-line:no-any
+        // eslint-disable-next-line @typescript-eslint/no-explicit-any
         this.bridge.on("thirdparty.location.remote", (protocol: string, fields: any, cb: (response: any) => void) => {
             this.tpGetLocation(protocol, fields)
-            .then(cb)
-            .catch((err) => log.warn("Failed to get remote locations", err));
+                .then(cb)
+                .catch((err) => log.warn("Failed to get remote locations", err));
         });
 
         // These are not supported.
@@ -86,7 +87,7 @@ export class MatrixRoomHandler {
         });
     }
 
-    public async OnAliasQueried(alias: string, roomId: string) {
+    public async OnAliasQueried(alias: string, roomId: string): Promise<void> {
         log.verbose(`Got OnAliasQueried for ${alias} ${roomId}`);
         let channel: Discord.GuildChannel;
         try {
@@ -124,9 +125,9 @@ export class MatrixRoomHandler {
         let delay = this.config.limits.roomGhostJoinDelay;
         for (const member of (channel as Discord.TextChannel).members.array()) {
             if (member.id === this.discord.GetBotId()) {
-              continue;
+                continue;
             }
-            promiseList.push((async () => {
+            promiseList.push((async (): Promise<void> => {
                 await Util.DelayedPromise(delay);
                 log.info(`UserSyncing ${member.id}`);
                 try {
@@ -144,7 +145,7 @@ export class MatrixRoomHandler {
         await Promise.all(promiseList);
     }
 
-    // tslint:disable-next-line no-any
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
     public async OnAliasQuery(alias: string): Promise<any> {
         const aliasLocalpart = alias.substr("#".length, alias.indexOf(":") - 1);
         log.info("Got request for #", aliasLocalpart);
@@ -166,6 +167,7 @@ export class MatrixRoomHandler {
         const instances = {};
         for (const guild of this.discord.GetGuilds()) {
             instances[guild.name] = {
+                /* eslint-disable @typescript-eslint/camelcase */
                 bot_user_id: this.botUserId,
                 desc: guild.name,
                 fields: {
@@ -173,9 +175,11 @@ export class MatrixRoomHandler {
                 },
                 icon: guild.iconURL || ICON_URL,
                 network_id: guild.id,
+                /* eslint-enable @typescript-eslint/camelcase */
             };
         }
         return {
+            /* eslint-disable @typescript-eslint/camelcase */
             field_types: {
                 // guild_name: {
                 //   regexp: "\S.{0,98}\S",
@@ -206,10 +210,11 @@ export class MatrixRoomHandler {
             instances,
             location_fields: ["guild_id", "channel_name"],
             user_fields: ["username", "discriminator"],
+            /* eslint-enable @typescript-eslint/camelcase */
         };
     }
 
-    // tslint:disable-next-line no-any
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any
     public async tpGetLocation(protocol: string, fields: any): Promise<IThirdPartyLookup[]> {
         log.info("Got location request ", protocol, fields);
         const chans = this.discord.ThirdpartySearchForChannels(fields.guild_id, fields.channel_name);
@@ -218,7 +223,7 @@ export class MatrixRoomHandler {
 
     private async joinRoom(intent: Intent, roomIdOrAlias: string, member?: Discord.GuildMember): Promise<void> {
         let currentSchedule = JOIN_ROOM_SCHEDULE[0];
-        const doJoin = async () => {
+        const doJoin = async (): Promise<void> => {
             await Util.DelayedPromise(currentSchedule);
             if (member) {
                 await this.discord.UserSyncroniser.JoinRoom(member, roomIdOrAlias);
@@ -226,7 +231,7 @@ export class MatrixRoomHandler {
                 await intent.joinRoom(roomIdOrAlias);
             }
         };
-        const errorHandler = async (err) => {
+        const errorHandler = async (err): Promise<void> => {
             log.error(`Error joining room ${roomIdOrAlias} as ${intent.userId}`);
             log.error(err);
             const idx = JOIN_ROOM_SCHEDULE.indexOf(currentSchedule);
@@ -250,17 +255,23 @@ export class MatrixRoomHandler {
         }
     }
 
-    private async createMatrixRoom(channel: Discord.TextChannel,
-                                   alias: string, aliasLocalpart: string) {
+    private async createMatrixRoom(
+        channel: Discord.TextChannel,
+        alias: string,
+        aliasLocalpart: string
+    ) {
         const remote = new RemoteStoreRoom(`discord_${channel.guild.id}_${channel.id}`, {
+            /* eslint-disable @typescript-eslint/camelcase */
             discord_channel: channel.id,
             discord_guild: channel.guild.id,
             discord_type: "text",
             update_icon: 1,
             update_name: 1,
             update_topic: 1,
+            /* eslint-enable @typescript-eslint/camelcase */
         });
         const creationOpts = {
+            /* eslint-disable @typescript-eslint/camelcase */
             initial_state: [
                 {
                     content: {
@@ -272,6 +283,7 @@ export class MatrixRoomHandler {
             ],
             room_alias_name: aliasLocalpart,
             visibility: this.config.room.defaultVisibility,
+            /* eslint-enable @typescript-eslint/camelcase */
         };
         // We need to tempoarily store this until we know the room_id.
         await this.roomStore.linkRooms(
diff --git a/src/metrics.ts b/src/metrics.ts
index 52f4028c0fc8983add64d80b427e9d96ab2320f2..785096b901cdb9bd7472b69f5ec16e83358f7a70 100644
--- a/src/metrics.ts
+++ b/src/metrics.ts
@@ -13,6 +13,7 @@ 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.
 */
+/* eslint-disable max-classes-per-file, @typescript-eslint/no-empty-function */
 
 import { Gauge, Counter, Histogram, default as promClient } from "prom-client";
 import { Log } from "./log";
diff --git a/src/store.ts b/src/store.ts
index c7574cb81dabb3db147dd77596144cf5d9d841cb..88cdc87a358c0d39fcc6110beaa5645561bda6bb 100644
--- a/src/store.ts
+++ b/src/store.ts
@@ -249,7 +249,7 @@ export class DiscordStore implements IAppserviceStorageProvider {
         }
     }
 
-    // tslint:disable-next-line no-any callable-types
+    // eslint-disable-next-line @typescript-eslint/no-explicit-any callable-types
     public async Get<T extends IDbData>(dbType: {new(): T; }, params: any): Promise<T|null> {
         const dType = new dbType();
         log.silly(`get <${dType.constructor.name} with params ${params}>`);