From 798bfac6439b340be88c537c451660ab9b67ecee Mon Sep 17 00:00:00 2001
From: Dennis Postma <dennis@directonline.io>
Date: Sat, 21 Sep 2024 15:39:50 +0200
Subject: [PATCH] #140 : Individual log files

---
 package-lock.json                             | 20 +++++------
 src/events/character/create.ts                |  6 ++--
 src/events/chat/gameMaster/teleportCommand.ts | 10 +++---
 src/events/chat/sendMessage.ts                |  9 +++--
 .../gameMaster/assetManager/object/upload.ts  |  7 ++--
 .../gameMaster/assetManager/sprite/delete.ts  |  6 ++--
 .../gameMaster/assetManager/tile/delete.ts    | 11 +++---
 .../gameMaster/assetManager/tile/upload.ts    |  5 ++-
 src/events/gameMaster/zoneEditor/create.ts    |  7 ++--
 src/events/gameMaster/zoneEditor/delete.ts    |  7 ++--
 src/events/gameMaster/zoneEditor/list.ts      |  7 ++--
 src/events/gameMaster/zoneEditor/request.ts   | 13 ++++---
 src/events/gameMaster/zoneEditor/update.ts    | 17 +++++----
 src/events/zone/characterJoin.ts              |  7 ++--
 src/events/zone/characterLeave.ts             | 12 +++----
 src/events/zone/characterMove.ts              | 10 +++---
 src/managers/userManager.ts                   |  4 +--
 src/managers/zoneManager.ts                   | 12 +++----
 src/middleware/authentication.ts              |  8 ++---
 src/repositories/zoneRepository.ts            | 16 ++++-----
 src/server.ts                                 | 29 ++++++---------
 .../character/characterMoveService.ts         |  5 ++-
 src/utilities/http.ts                         |  8 ++---
 src/utilities/logger.ts                       | 35 ++++++++++++++++---
 24 files changed, 136 insertions(+), 135 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index d104c7b..ab99471 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1141,9 +1141,9 @@
       }
     },
     "node_modules/engine.io": {
-      "version": "6.5.5",
-      "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz",
-      "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==",
+      "version": "6.6.1",
+      "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.1.tgz",
+      "integrity": "sha512-NEpDCw9hrvBW+hVEOK4T7v0jFJ++KgtPl4jKFwsZVfG1XhS0dCrSb3VMb9gPAd7VAdW52VT1EnaNiU2vM8C0og==",
       "license": "MIT",
       "dependencies": {
         "@types/cookie": "^0.4.1",
@@ -1789,9 +1789,9 @@
       }
     },
     "node_modules/nodemon": {
-      "version": "3.1.6",
-      "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.6.tgz",
-      "integrity": "sha512-C8ymJbXpTTinxjWuMfMxw0rZhTn/r7ypSGldQyqPEgDEaVwAthqC0aodsMwontnAInN9TuPwRLeBoyhmfv+iSA==",
+      "version": "3.1.7",
+      "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz",
+      "integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
@@ -2317,16 +2317,16 @@
       }
     },
     "node_modules/socket.io": {
-      "version": "4.7.5",
-      "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz",
-      "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==",
+      "version": "4.8.0",
+      "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.0.tgz",
+      "integrity": "sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA==",
       "license": "MIT",
       "dependencies": {
         "accepts": "~1.3.4",
         "base64id": "~2.0.0",
         "cors": "~2.8.5",
         "debug": "~4.3.2",
-        "engine.io": "~6.5.2",
+        "engine.io": "~6.6.0",
         "socket.io-adapter": "~2.5.2",
         "socket.io-parser": "~4.2.4"
       },
diff --git a/src/events/character/create.ts b/src/events/character/create.ts
index b3b6e0f..0417f86 100644
--- a/src/events/character/create.ts
+++ b/src/events/character/create.ts
@@ -4,7 +4,7 @@ import { Character } from '@prisma/client'
 import CharacterRepository from '../../repositories/characterRepository'
 import { ZCharacterCreate } from '../../utilities/zodTypes'
 import prisma from '../../utilities/prisma'
-import logger from '../../utilities/logger'
+import { gameLogger } from '../../utilities/logger'
 
 export default function (socket: TSocket, io: Server) {
   socket.on('character:create', async (data: any) => {
@@ -41,10 +41,10 @@ export default function (socket: TSocket, io: Server) {
       socket.emit('character:create:success')
       socket.emit('character:list', characters)
 
-      logger.info('character:create success')
+      gameLogger.info('character:create success')
     } catch (error: any) {
       console.log(error)
-      logger.error(`character:create error: ${error.message}`)
+      gameLogger.error(`character:create error: ${error.message}`)
       return socket.emit('notification', { message: 'Could not create character. Please try again (later).' })
     }
   })
diff --git a/src/events/chat/gameMaster/teleportCommand.ts b/src/events/chat/gameMaster/teleportCommand.ts
index a806052..0c65aeb 100644
--- a/src/events/chat/gameMaster/teleportCommand.ts
+++ b/src/events/chat/gameMaster/teleportCommand.ts
@@ -1,11 +1,9 @@
 import { Server } from 'socket.io'
-import { ExtendedCharacter, TSocket } from '../../../utilities/types'
+import { TSocket } from '../../../utilities/types'
 import { getArgs, isCommand } from '../../../utilities/chat'
-import CharacterRepository from '../../../repositories/characterRepository'
 import ZoneRepository from '../../../repositories/zoneRepository'
 import CharacterManager from '../../../managers/characterManager'
-import logger from '../../../utilities/logger'
-import prisma from '../../../utilities/prisma'
+import { gameMasterLogger } from '../../../utilities/logger'
 
 type TypePayload = {
   message: string
@@ -76,11 +74,11 @@ export default class TeleportCommandEvent {
       })
 
       this.socket.emit('notification', { title: 'Server message', message: `You have been teleported to ${zone.name}` })
-      logger.info('teleport', `Character ${character.id} teleported to zone ${zone.id}`)
+      gameMasterLogger.info('teleport', `Character ${character.id} teleported to zone ${zone.id}`)
 
       callback(true)
     } catch (error: any) {
-      logger.error(`Error in teleport command: ${error.message}`)
+      gameMasterLogger.error(`Error in teleport command: ${error.message}`)
       this.socket.emit('notification', { title: 'Server message', message: 'An error occurred while teleporting' })
     }
   }
diff --git a/src/events/chat/sendMessage.ts b/src/events/chat/sendMessage.ts
index 3c1e87c..ffc00b3 100644
--- a/src/events/chat/sendMessage.ts
+++ b/src/events/chat/sendMessage.ts
@@ -3,8 +3,7 @@ import { TSocket } from '../../utilities/types'
 import CharacterRepository from '../../repositories/characterRepository'
 import ZoneRepository from '../../repositories/zoneRepository'
 import { isCommand } from '../../utilities/chat'
-import logger from '../../utilities/logger'
-import CharacterManager from '../../managers/characterManager'
+import { gameLogger } from '../../utilities/logger'
 
 type TypePayload = {
   message: string
@@ -29,14 +28,14 @@ export default class ChatMessageEvent {
 
       const character = await CharacterRepository.getByUserAndId(this.socket.user?.id as number, this.socket.characterId as number)
       if (!character) {
-        logger.error('chat:send_message error', 'Character not found')
+        gameLogger.error('chat:send_message error', 'Character not found')
         callback(false)
         return
       }
 
       const zone = await ZoneRepository.getById(character.zoneId)
       if (!zone) {
-        logger.error('chat:send_message error', 'Zone not found')
+        gameLogger.error('chat:send_message error', 'Zone not found')
         callback(false)
         return
       }
@@ -48,7 +47,7 @@ export default class ChatMessageEvent {
         message: data.message
       })
     } catch (error: any) {
-      logger.error('chat:send_message error', error.message)
+      gameLogger.error('chat:send_message error', error.message)
       callback(false)
     }
   }
diff --git a/src/events/gameMaster/assetManager/object/upload.ts b/src/events/gameMaster/assetManager/object/upload.ts
index 4309d29..8fd0b3f 100644
--- a/src/events/gameMaster/assetManager/object/upload.ts
+++ b/src/events/gameMaster/assetManager/object/upload.ts
@@ -5,9 +5,8 @@ import path from 'path'
 import fs from 'fs/promises'
 import prisma from '../../../../utilities/prisma'
 import sharp from 'sharp'
-import logger from '../../../../utilities/logger'
-import CharacterManager from '../../../../managers/characterManager'
 import characterRepository from '../../../../repositories/characterRepository'
+import { gameMasterLogger } from '../../../../utilities/logger'
 
 interface IObjectData {
   [key: string]: Buffer
@@ -58,14 +57,14 @@ export default class ObjectUploadEvent {
         const finalFilePath = path.join(public_folder, filename)
         await writeFile(finalFilePath, objectData)
 
-        logger.info('gm:object:upload', `Object ${key} uploaded with id ${uuid}`)
+        gameMasterLogger.info('gm:object:upload', `Object ${key} uploaded with id ${uuid}`)
       })
 
       await Promise.all(uploadPromises)
 
       callback(true)
     } catch (error: any) {
-      logger.error('gm:object:upload error', error.message)
+      gameMasterLogger.error('gm:object:upload error', error.message)
       callback(false)
     }
   }
diff --git a/src/events/gameMaster/assetManager/sprite/delete.ts b/src/events/gameMaster/assetManager/sprite/delete.ts
index 9ddf02c..8a4cc90 100644
--- a/src/events/gameMaster/assetManager/sprite/delete.ts
+++ b/src/events/gameMaster/assetManager/sprite/delete.ts
@@ -3,8 +3,8 @@ import { TSocket } from '../../../../utilities/types'
 import fs from 'fs'
 import path from 'path'
 import prisma from '../../../../utilities/prisma'
-import logger from '../../../../utilities/logger'
 import CharacterManager from '../../../../managers/characterManager'
+import { gameMasterLogger } from '../../../../utilities/logger'
 
 type Payload = {
   id: string
@@ -34,10 +34,10 @@ export default class GMSpriteDeleteEvent {
       await this.deleteSpriteFolder(data.id)
       await this.deleteSpriteFromDatabase(data.id)
 
-      logger.info(`Sprite ${data.id} deleted.`)
+      gameMasterLogger.info(`Sprite ${data.id} deleted.`)
       callback(true)
     } catch (error: any) {
-      logger.error('gm:sprite:delete error', error.message)
+      gameMasterLogger.error('gm:sprite:delete error', error.message)
       callback(false)
     }
   }
diff --git a/src/events/gameMaster/assetManager/tile/delete.ts b/src/events/gameMaster/assetManager/tile/delete.ts
index 08aafad..bdb5eb7 100644
--- a/src/events/gameMaster/assetManager/tile/delete.ts
+++ b/src/events/gameMaster/assetManager/tile/delete.ts
@@ -3,9 +3,8 @@ import fs from 'fs/promises'
 import { Server } from 'socket.io'
 import { TSocket } from '../../../../utilities/types'
 import prisma from '../../../../utilities/prisma'
-import logger from '../../../../utilities/logger'
-import CharacterManager from '../../../../managers/characterManager'
 import characterRepository from '../../../../repositories/characterRepository'
+import { gameMasterLogger } from '../../../../utilities/logger'
 
 type Payload = {
   id: string
@@ -34,14 +33,14 @@ export default class GMTileDeleteEvent {
     }
 
     try {
-      logger.info(`Deleting tile ${data.id}`)
+      gameMasterLogger.info(`Deleting tile ${data.id}`)
       await this.deleteTileFromDatabase(data.id)
       await this.deleteTileFile(data.id)
 
-      logger.info(`Tile ${data.id} deleted successfully.`)
+      gameMasterLogger.info(`Tile ${data.id} deleted successfully.`)
       callback(true)
     } catch (error: any) {
-      logger.error('gm:tile:delete error', error.message)
+      gameMasterLogger.error('gm:tile:delete error', error.message)
       callback(false)
     }
   }
@@ -62,7 +61,7 @@ export default class GMTileDeleteEvent {
       if (error.code !== 'ENOENT') {
         throw error
       }
-      logger.warn(`File ${finalFilePath} does not exist.`)
+      gameMasterLogger.warn(`File ${finalFilePath} does not exist.`)
     }
   }
 }
diff --git a/src/events/gameMaster/assetManager/tile/upload.ts b/src/events/gameMaster/assetManager/tile/upload.ts
index 86c8aae..b215672 100644
--- a/src/events/gameMaster/assetManager/tile/upload.ts
+++ b/src/events/gameMaster/assetManager/tile/upload.ts
@@ -4,9 +4,8 @@ import { writeFile } from 'node:fs/promises'
 import path from 'path'
 import fs from 'fs/promises'
 import prisma from '../../../../utilities/prisma'
-import CharacterManager from '../../../../managers/characterManager'
 import characterRepository from '../../../../repositories/characterRepository'
-import logger from '../../../../utilities/logger'
+import { gameMasterLogger } from '../../../../utilities/logger'
 
 interface ITileData {
   [key: string]: Buffer
@@ -48,7 +47,7 @@ export default function (socket: TSocket, io: Server) {
 
       callback(true)
     } catch (error) {
-      console.error('Error uploading tile:', error)
+      gameMasterLogger.error('Error uploading tile:', error)
       callback(false)
     }
   })
diff --git a/src/events/gameMaster/zoneEditor/create.ts b/src/events/gameMaster/zoneEditor/create.ts
index cfbe54e..73b4be2 100644
--- a/src/events/gameMaster/zoneEditor/create.ts
+++ b/src/events/gameMaster/zoneEditor/create.ts
@@ -3,9 +3,8 @@ import { TSocket } from '../../../utilities/types'
 import ZoneRepository from '../../../repositories/zoneRepository'
 import { Zone } from '@prisma/client'
 import prisma from '../../../utilities/prisma'
-import CharacterManager from '../../../managers/characterManager'
 import characterRepository from '../../../repositories/characterRepository'
-import logger from '../../../utilities/logger'
+import { gameMasterLogger } from '../../../utilities/logger'
 
 type Payload = {
   name: string
@@ -24,11 +23,11 @@ export default function (socket: TSocket, io: Server) {
     if (!character) return
 
     if (character.role !== 'gm') {
-      logger.info(`User ${character.id} tried to create zone but is not a game master.`)
+      gameMasterLogger.info(`User ${character.id} tried to create zone but is not a game master.`)
       return
     }
 
-    logger.info(`User ${character.id} has created a new zone via zone editor.`)
+    gameMasterLogger.info(`User ${character.id} has created a new zone via zone editor.`)
 
     let zoneList: Zone[] = []
     try {
diff --git a/src/events/gameMaster/zoneEditor/delete.ts b/src/events/gameMaster/zoneEditor/delete.ts
index c2cfb58..1b5acb0 100644
--- a/src/events/gameMaster/zoneEditor/delete.ts
+++ b/src/events/gameMaster/zoneEditor/delete.ts
@@ -2,9 +2,8 @@ import { Server } from 'socket.io'
 import { TSocket } from '../../../utilities/types'
 import ZoneRepository from '../../../repositories/zoneRepository'
 import prisma from '../../../utilities/prisma'
-import CharacterManager from '../../../managers/characterManager'
 import characterRepository from '../../../repositories/characterRepository'
-import logger from '../../../utilities/logger'
+import { gameMasterLogger } from '../../../utilities/logger'
 
 type Payload = {
   zoneId: number
@@ -21,11 +20,11 @@ export default function (socket: TSocket, io: Server) {
     if (!character) return
     
     if (character.role !== 'gm') {
-      logger.info(`User ${character.id} tried to delete zone but is not a game master.`)
+      gameMasterLogger.info(`User ${character.id} tried to delete zone but is not a game master.`)
       return
     }
 
-    logger.info(`User ${character.id} has deleted a zone via zone editor.`)
+    gameMasterLogger.info(`User ${character.id} has deleted a zone via zone editor.`)
 
     try {
       const zone = await ZoneRepository.getById(data.zoneId)
diff --git a/src/events/gameMaster/zoneEditor/list.ts b/src/events/gameMaster/zoneEditor/list.ts
index b333f81..7420796 100644
--- a/src/events/gameMaster/zoneEditor/list.ts
+++ b/src/events/gameMaster/zoneEditor/list.ts
@@ -2,9 +2,8 @@ import { Server } from 'socket.io'
 import { TSocket } from '../../../utilities/types'
 import { Zone } from '@prisma/client'
 import ZoneRepository from '../../../repositories/zoneRepository'
-import CharacterManager from '../../../managers/characterManager'
 import characterRepository from '../../../repositories/characterRepository'
-import logger from '../../../utilities/logger'
+import { gameMasterLogger } from '../../../utilities/logger'
 
 interface IPayload {}
 
@@ -19,11 +18,11 @@ export default function (socket: TSocket, io: Server) {
     if (!character) return
     
     if (character.role !== 'gm') {
-      logger.info(`User ${character.id} tried to list zones but is not a game master.`)
+      gameMasterLogger.info(`User ${character.id} tried to list zones but is not a game master.`)
       return
     }
 
-    logger.info(`User ${character.id} has requested zone list via zone editor.`)
+    gameMasterLogger.info(`User ${character.id} has requested zone list via zone editor.`)
 
     try {
       const zones = await ZoneRepository.getAll()
diff --git a/src/events/gameMaster/zoneEditor/request.ts b/src/events/gameMaster/zoneEditor/request.ts
index ad1c88f..289a1ad 100644
--- a/src/events/gameMaster/zoneEditor/request.ts
+++ b/src/events/gameMaster/zoneEditor/request.ts
@@ -1,10 +1,9 @@
 import { Server } from 'socket.io'
 import { TSocket } from '../../../utilities/types'
 import ZoneRepository from '../../../repositories/zoneRepository'
-import { Character, Zone } from '@prisma/client'
-import CharacterManager from '../../../managers/characterManager'
+import { Zone } from '@prisma/client'
 import characterRepository from '../../../repositories/characterRepository'
-import logger from '../../../utilities/logger'
+import { gameMasterLogger } from '../../../utilities/logger'
 
 interface IPayload {
   zoneId: number
@@ -21,14 +20,14 @@ export default function (socket: TSocket, io: Server) {
     if (!character) return
 
     if (character.role !== 'gm') {
-      logger.info(`User ${character!.id} tried to request zone but is not a game master.`)
+      gameMasterLogger.info(`User ${character!.id} tried to request zone but is not a game master.`)
       return
     }
 
-    logger.info(`User ${character.id} has requested zone via zone editor.`)
+    gameMasterLogger.info(`User ${character.id} has requested zone via zone editor.`)
 
     if (!data.zoneId) {
-      logger.info(`User ${character.id} tried to request zone but did not provide a zone id.`)
+      gameMasterLogger.info(`User ${character.id} tried to request zone but did not provide a zone id.`)
       return
     }
 
@@ -36,7 +35,7 @@ export default function (socket: TSocket, io: Server) {
       const zone = await ZoneRepository.getById(data.zoneId)
 
       if (!zone) {
-        logger.info(`User ${character.id} tried to request zone ${data.zoneId} but it does not exist.`)
+        gameMasterLogger.info(`User ${character.id} tried to request zone ${data.zoneId} but it does not exist.`)
         return
       }
 
diff --git a/src/events/gameMaster/zoneEditor/update.ts b/src/events/gameMaster/zoneEditor/update.ts
index acb242a..436a30a 100644
--- a/src/events/gameMaster/zoneEditor/update.ts
+++ b/src/events/gameMaster/zoneEditor/update.ts
@@ -1,12 +1,11 @@
 import { Server } from 'socket.io'
 import { TSocket } from '../../../utilities/types'
 import ZoneRepository from '../../../repositories/zoneRepository'
-import { Zone, ZoneEventTile, ZoneEventTileType, ZoneObject } from '@prisma/client'
+import { Zone, ZoneEventTileType, ZoneObject } from '@prisma/client'
 import prisma from '../../../utilities/prisma'
 import zoneManager from '../../../managers/zoneManager'
-import logger from '../../../utilities/logger'
-import CharacterManager from '../../../managers/characterManager'
 import characterRepository from '../../../repositories/characterRepository'
+import { gameMasterLogger } from '../../../utilities/logger'
 
 interface IPayload {
   zoneId: number
@@ -39,14 +38,14 @@ export default function (socket: TSocket, io: Server) {
     if (!character) return
 
     if (character.role !== 'gm') {
-      logger.info(`User ${character.id} tried to update zone but is not a game master.`)
+      gameMasterLogger.info(`User ${character.id} tried to update zone but is not a game master.`)
       return
     }
 
-    logger.info(`User ${character.id} has updated zone via zone editor.`)
+    gameMasterLogger.info(`User ${character.id} has updated zone via zone editor.`)
 
     if (!data.zoneId) {
-      logger.info(`User ${character.id} tried to update zone but did not provide a zone id.`)
+      gameMasterLogger.info(`User ${character.id} tried to update zone but did not provide a zone id.`)
       return
     }
 
@@ -54,7 +53,7 @@ export default function (socket: TSocket, io: Server) {
       let zone = await ZoneRepository.getById(data.zoneId)
 
       if (!zone) {
-        logger.info(`User ${character.id} tried to update zone ${data.zoneId} but it does not exist.`)
+        gameMasterLogger.info(`User ${character.id} tried to update zone ${data.zoneId} but it does not exist.`)
         return
       }
 
@@ -108,7 +107,7 @@ export default function (socket: TSocket, io: Server) {
       zone = await ZoneRepository.getById(data.zoneId)
 
       if (!zone) {
-        logger.info(`User ${character.id} tried to update zone ${data.zoneId} but it does not exist.`)
+        gameMasterLogger.info(`User ${character.id} tried to update zone ${data.zoneId} but it does not exist.`)
         return
       }
 
@@ -117,7 +116,7 @@ export default function (socket: TSocket, io: Server) {
       zoneManager.unloadZone(data.zoneId)
       await zoneManager.loadZone(zone)
     } catch (error: any) {
-      logger.error(`Error updating zone: ${error.message}`)
+      gameMasterLogger.error(`Error updating zone: ${error.message}`)
     }
   })
 }
diff --git a/src/events/zone/characterJoin.ts b/src/events/zone/characterJoin.ts
index 914b5d8..db45332 100644
--- a/src/events/zone/characterJoin.ts
+++ b/src/events/zone/characterJoin.ts
@@ -1,10 +1,9 @@
 import { Server } from 'socket.io'
-import { ExtendedCharacter, TSocket } from '../../utilities/types'
+import { TSocket } from '../../utilities/types'
 import ZoneRepository from '../../repositories/zoneRepository'
-import ZoneManager from '../../managers/zoneManager'
 import { Character, Zone } from '@prisma/client'
-import logger from '../../utilities/logger'
 import CharacterManager from '../../managers/characterManager'
+import { gameLogger } from '../../utilities/logger'
 
 interface IPayload {
   zoneId: number
@@ -58,7 +57,7 @@ export default function (socket: TSocket, io: Server) {
       // send over zone and characters to socket
       callback({ zone, characters: CharacterManager.getCharactersInZone(zone) })
     } catch (error: any) {
-      logger.error(`Error requesting zone: ${error.message}`)
+      gameLogger.error(`Error requesting zone: ${error.message}`)
       socket.disconnect()
     }
   })
diff --git a/src/events/zone/characterLeave.ts b/src/events/zone/characterLeave.ts
index 187003e..881bc82 100644
--- a/src/events/zone/characterLeave.ts
+++ b/src/events/zone/characterLeave.ts
@@ -2,7 +2,7 @@ import { Server } from 'socket.io'
 import { TSocket } from '../../utilities/types'
 import ZoneRepository from '../../repositories/zoneRepository'
 import CharacterManager from '../../managers/characterManager'
-import logger from '../../utilities/logger'
+import { gameLogger } from '../../utilities/logger'
 
 export default class ZoneLeaveEvent {
   constructor(
@@ -18,19 +18,19 @@ export default class ZoneLeaveEvent {
     try {
       const character = CharacterManager.getCharacterFromSocket(this.socket);
       if (!character) {
-        logger.error('zone:character:leave error', 'Character not found')
+        gameLogger.error('zone:character:leave error', 'Character not found')
         return
       }
 
       if (!character.zoneId) {
-        logger.error('zone:character:leave error', 'Character not in a zone')
+        gameLogger.error('zone:character:leave error', 'Character not in a zone')
         return
       }
 
       const zone = await ZoneRepository.getById(character.zoneId)
 
       if (!zone) {
-        logger.error('zone:character:leave error', 'Zone not found')
+        gameLogger.error('zone:character:leave error', 'Zone not found')
         return
       }
 
@@ -42,9 +42,9 @@ export default class ZoneLeaveEvent {
       // remove character from zone manager
       await CharacterManager.removeCharacter(character)
 
-      logger.info('zone:character:leave', `Character ${character.id} left zone ${zone.id}`)
+      gameLogger.info('zone:character:leave', `Character ${character.id} left zone ${zone.id}`)
     } catch (error: any) {
-      logger.error('zone:character:leave error', error.message)
+      gameLogger.error('zone:character:leave error', error.message)
     }
   }
 }
diff --git a/src/events/zone/characterMove.ts b/src/events/zone/characterMove.ts
index 52fcb30..9634d94 100644
--- a/src/events/zone/characterMove.ts
+++ b/src/events/zone/characterMove.ts
@@ -5,10 +5,8 @@ import { ZoneEventTileService } from '../../services/zoneEventTileService'
 import prisma from '../../utilities/prisma'
 import { ZoneEventTile, ZoneEventTileTeleport } from '@prisma/client'
 import Rotation from '../../utilities/character/rotation'
-import logger from '../../utilities/logger'
 import CharacterManager from '../../managers/characterManager'
-import zoneManager from '../../managers/zoneManager'
-import ZoneManager from '../../managers/zoneManager'
+import { gameLogger } from '../../utilities/logger'
 
 export type ZoneEventTileWithTeleport = ZoneEventTile & {
   teleport: ZoneEventTileTeleport
@@ -35,12 +33,12 @@ export default class CharacterMove {
   private async handleCharacterMove({ positionX, positionY }: { positionX: number; positionY: number }): Promise<void> {
     let character = CharacterManager.getCharacterFromSocket(this.socket)
     if (!character) {
-      logger.error('character:move error', 'Character not found')
+      gameLogger.error('character:move error', 'Character not found')
       return
     }
 
     if (!character) {
-      logger.error('character:move error', 'character has not been initialized?')
+      gameLogger.error('character:move error', 'character has not been initialized?')
       return
     }
 
@@ -127,7 +125,7 @@ export default class CharacterMove {
   private async handleZoneEventTile(zoneEventTile: ZoneEventTileWithTeleport): Promise<void> {
     const character = CharacterManager.getCharacterFromSocket(this.socket)
     if (!character) {
-      logger.error('character:move error', 'Character not found')
+      gameLogger.error('character:move error', 'Character not found')
       return
     }
 
diff --git a/src/managers/userManager.ts b/src/managers/userManager.ts
index 3c1c29b..135da63 100644
--- a/src/managers/userManager.ts
+++ b/src/managers/userManager.ts
@@ -1,5 +1,5 @@
 import { User } from '@prisma/client'
-import logger from '../utilities/logger'
+import { appLogger } from '../utilities/logger'
 
 type TLoggedInUsers = {
   users: User[]
@@ -10,7 +10,7 @@ class UserManager {
 
   // Method to initialize user manager
   public async boot() {
-    logger.info('User manager loaded')
+    appLogger.info('User manager loaded')
   }
 
   // Function that adds user to logged in users
diff --git a/src/managers/zoneManager.ts b/src/managers/zoneManager.ts
index 4a8e8ee..3d41afd 100644
--- a/src/managers/zoneManager.ts
+++ b/src/managers/zoneManager.ts
@@ -1,11 +1,9 @@
-import { Zone, ZoneEventTileTeleport, ZoneEventTileType } from '@prisma/client'
+import { Zone } from '@prisma/client'
 import ZoneRepository from '../repositories/zoneRepository'
 import ZoneService from '../services/zoneService'
-import logger from '../utilities/logger'
 import LoadedZone from '../models/loadedZone'
 import zoneRepository from '../repositories/zoneRepository'
-import { beforeEach } from 'node:test'
-import prisma from '../utilities/prisma'
+import { gameMasterLogger } from '../utilities/logger'
 
 class ZoneManager {
   private loadedZones: LoadedZone[] = []
@@ -23,7 +21,7 @@ class ZoneManager {
       await this.loadZone(zone)
     }
 
-    logger.info('Zone manager loaded')
+    gameMasterLogger.info('Zone manager loaded')
   }
 
   public async getZoneAssets(zone: Zone): Promise<ZoneAssets> {
@@ -46,13 +44,13 @@ class ZoneManager {
     const loadedZone = new LoadedZone(zone)
     this.loadedZones.push(loadedZone)
     await this.getZoneAssets(zone)
-    logger.info(`Zone ID ${zone.id} loaded`)
+    gameMasterLogger.info(`Zone ID ${zone.id} loaded`)
   }
 
   // Method to handle individual zoneEditor unloading
   public unloadZone(zoneId: number) {
     this.loadedZones = this.loadedZones.filter((loadedZone) => loadedZone.getZone().id !== zoneId)
-    logger.info(`Zone ID ${zoneId} unloaded`)
+    gameMasterLogger.info(`Zone ID ${zoneId} unloaded`)
   }
 
   // Getter for loaded zones
diff --git a/src/middleware/authentication.ts b/src/middleware/authentication.ts
index db2d7e5..dd2270c 100644
--- a/src/middleware/authentication.ts
+++ b/src/middleware/authentication.ts
@@ -3,7 +3,7 @@ import { TSocket } from '../utilities/types'
 import config from '../utilities/config'
 import UserRepository from '../repositories/userRepository'
 import { User } from '@prisma/client'
-import logger from '../utilities/logger'
+import { gameLogger } from '../utilities/logger'
 
 /**
  * Socket io jwt auth middleware
@@ -12,7 +12,7 @@ import logger from '../utilities/logger'
  */
 export async function Authentication(socket: TSocket, next: any) {
   if (!socket.request.headers.cookie) {
-    logger.warn('No cookie provided')
+    gameLogger.warn('No cookie provided')
     return next(new Error('Authentication error'))
   }
 
@@ -33,7 +33,7 @@ export async function Authentication(socket: TSocket, next: any) {
   if (token) {
     verify(token, config.JWT_SECRET, async (err: any, decoded: any) => {
       if (err) {
-        logger.error('Invalid token')
+        gameLogger.error('Invalid token')
         return next(new Error('Authentication error'))
       }
 
@@ -41,7 +41,7 @@ export async function Authentication(socket: TSocket, next: any) {
       next()
     })
   } else {
-    logger.warn('No token provided')
+    gameLogger.warn('No token provided')
     return next(new Error('Authentication error'))
   }
 }
diff --git a/src/repositories/zoneRepository.ts b/src/repositories/zoneRepository.ts
index b944b2a..ec3cd42 100644
--- a/src/repositories/zoneRepository.ts
+++ b/src/repositories/zoneRepository.ts
@@ -1,14 +1,14 @@
-import { Zone, ZoneEventTile, ZoneEventTileTeleport, ZoneEventTileType, ZoneObject } from '@prisma/client'
+import { Zone, ZoneEventTile, ZoneEventTileType, ZoneObject } from '@prisma/client'
 import prisma from '../utilities/prisma'
-import logger from '../utilities/logger'
 import { ZoneEventTileWithTeleport } from '../events/zone/characterMove'
+import { appLogger } from '../utilities/logger'
 
 class ZoneRepository {
   async getFirst(): Promise<Zone | null> {
     try {
       return await prisma.zone.findFirst()
     } catch (error: any) {
-      logger.error(`Failed to get first zone: ${error.message}`)
+      appLogger.error(`Failed to get first zone: ${error.message}`)
       return null
     }
   }
@@ -17,7 +17,7 @@ class ZoneRepository {
     try {
       return await prisma.zone.findMany()
     } catch (error: any) {
-      logger.error(`Failed to get all zone: ${error.message}`)
+      appLogger.error(`Failed to get all zone: ${error.message}`)
       return []
     }
   }
@@ -43,7 +43,7 @@ class ZoneRepository {
         }
       })
     } catch (error: any) {
-      logger.error(`Failed to get zone by id: ${error.message}`)
+      appLogger.error(`Failed to get zone by id: ${error.message}`)
       return null
     }
   }
@@ -56,7 +56,7 @@ class ZoneRepository {
         }
       })
     } catch (error: any) {
-      logger.error(`Failed to get zone event tiles: ${error.message}`)
+      appLogger.error(`Failed to get zone event tiles: ${error.message}`)
       return []
     }
   }
@@ -71,7 +71,7 @@ class ZoneRepository {
         include: { teleport: true }
       })) as unknown as ZoneEventTileWithTeleport[]
     } catch (error: any) {
-      logger.error(`Failed to get zone event tiles: ${error.message}`)
+      appLogger.error(`Failed to get zone event tiles: ${error.message}`)
       return []
     }
   }
@@ -84,7 +84,7 @@ class ZoneRepository {
         }
       })
     } catch (error: any) {
-      logger.error(`Failed to get zone objects: ${error.message}`)
+      appLogger.error(`Failed to get zone objects: ${error.message}`)
       return []
     }
   }
diff --git a/src/server.ts b/src/server.ts
index 9da89d0..19fa7da 100644
--- a/src/server.ts
+++ b/src/server.ts
@@ -13,7 +13,7 @@ import UserManager from './managers/userManager'
 import { Authentication } from './middleware/authentication'
 // import CommandManager from './managers/CommandManager'
 import { Dirent } from 'node:fs'
-import logger from './utilities/logger'
+import { appLogger, watchLogs } from './utilities/logger'
 import CharacterManager from './managers/characterManager'
 
 export class Server {
@@ -39,31 +39,22 @@ export class Server {
    */
   public async start() {
     // Read log file and print to console for debugging
-    const logFile = path.join(__dirname, '../logs/app.log')
-
-    fs.watchFile(logFile, (curr, prev) => {
-      if (curr.size > prev.size) {
-        const stream = fs.createReadStream(logFile, { start: prev.size, end: curr.size })
-        stream.on('data', (chunk) => {
-          console.log(chunk.toString())
-        })
-      }
-    })
+    watchLogs()
 
     // Check prisma connection
     try {
       await prisma.$connect()
-      logger.info('Database connected')
+      appLogger.info('Database connected')
     } catch (error: any) {
-      logger.error(`Database connection failed: ${error.message}`)
+      appLogger.error(`Database connection failed: ${error.message}`)
     }
 
     // Start the server
     try {
       this.http.listen(config.PORT, config.HOST)
-      logger.info(`Socket.IO running on port ${config.PORT}`)
+      appLogger.info(`Socket.IO running on port ${config.PORT}`)
     } catch (error: any) {
-      logger.error(`Socket.IO failed to start: ${error.message}`)
+      appLogger.error(`Socket.IO failed to start: ${error.message}`)
     }
 
     // Add http API routes
@@ -95,7 +86,7 @@ export class Server {
     try {
       await this.loadEventHandlers(eventsPath, socket)
     } catch (error: any) {
-      logger.error(`Failed to load event handlers: ${error.message}`)
+      appLogger.error(`Failed to load event handlers: ${error.message}`)
     }
   }
 
@@ -121,10 +112,10 @@ export class Server {
               module.default(socket, this.io)
             }
           } else {
-            logger.warn(`Unrecognized export in ${file.name}`)
+            appLogger.warn(`Unrecognized export in ${file.name}`)
           }
         } catch (error: any) {
-          logger.error(`Error loading event handler ${file.name}: ${error.message}`)
+          appLogger.error(`Error loading event handler ${file.name}: ${error.message}`)
         }
       }
     }
@@ -135,4 +126,4 @@ export class Server {
 const server = new Server()
 server.start()
 
-console.log('Server started')
+appLogger.info('Server started')
diff --git a/src/services/character/characterMoveService.ts b/src/services/character/characterMoveService.ts
index e360263..2dd47cb 100644
--- a/src/services/character/characterMoveService.ts
+++ b/src/services/character/characterMoveService.ts
@@ -1,9 +1,8 @@
 import { ExtendedCharacter } from '../../utilities/types'
 import { AStar } from '../../utilities/character/aStar'
 import ZoneManager from '../../managers/zoneManager'
-import prisma from '../../utilities/prisma'
 import Rotation from '../../utilities/character/rotation'
-import logger from '../../utilities/logger'
+import { gameLogger } from '../../utilities/logger'
 
 export class CharacterMoveService {
   public updatePosition(character: ExtendedCharacter, position: { x: number; y: number }, newZoneId?: number) {
@@ -28,7 +27,7 @@ export class CharacterMoveService {
   public async calculatePath(character: ExtendedCharacter, targetX: number, targetY: number): Promise<Array<{ x: number; y: number }> | null> {
     const grid = await ZoneManager.getZoneById(character.zoneId)?.getGrid()
     if (!grid?.length) {
-      logger.error('character:move error', 'Grid not found or empty')
+      gameLogger.error('character:move error', 'Grid not found or empty')
       return null
     }
 
diff --git a/src/utilities/http.ts b/src/utilities/http.ts
index 17430cc..75a1e70 100644
--- a/src/utilities/http.ts
+++ b/src/utilities/http.ts
@@ -9,9 +9,9 @@ import tileRepository from '../repositories/tileRepository'
 import objectRepository from '../repositories/objectRepository'
 import spriteRepository from '../repositories/spriteRepository'
 import fs from 'fs'
-import logger from './logger'
 import zoneRepository from '../repositories/zoneRepository'
 import zoneManager from '../managers/zoneManager'
+import { httpLogger } from './logger'
 
 async function addHttpRoutes(app: Application) {
   /**
@@ -118,13 +118,13 @@ async function addHttpRoutes(app: Application) {
     }
 
     if (!fs.existsSync(assetPath)) {
-      logger.error(`File not found: ${assetPath}`)
+      httpLogger.error(`File not found: ${assetPath}`)
       return res.status(404).send('Asset not found')
     }
 
     res.sendFile(assetPath, (err) => {
       if (err) {
-        logger.error('Error sending file:', err)
+        httpLogger.error('Error sending file:', err)
         res.status(500).send('Error downloading the asset')
       }
     })
@@ -179,7 +179,7 @@ async function addHttpRoutes(app: Application) {
     return res.status(400).json({ message: 'Failed to register user' })
   })
 
-  logger.info('Web routes added')
+  httpLogger.info('Web routes added')
 }
 
 export { addHttpRoutes }
diff --git a/src/utilities/logger.ts b/src/utilities/logger.ts
index ba99f3d..d042f00 100644
--- a/src/utilities/logger.ts
+++ b/src/utilities/logger.ts
@@ -1,11 +1,17 @@
 import pino from 'pino'
+import fs from 'fs'
+import path from 'path'
 
-const logger = pino({
+// Array of log types
+const LOG_TYPES = ['http', 'game', 'gameMaster', 'app'] as const
+type LogType = typeof LOG_TYPES[number]
+
+const createLogger = (name: LogType) => pino({
   level: process.env.LOG_LEVEL || 'debug',
   transport: {
     target: 'pino/file',
     options: {
-      destination: './logs/app.log',
+      destination: `./logs/${name}.log`,
       mkdir: true
     }
   },
@@ -15,7 +21,28 @@ const logger = pino({
     }
   },
   timestamp: pino.stdTimeFunctions.isoTime,
-  base: null // This will prevent hostname and pid from being included
+  base: null
 })
 
-export default logger
+// Create logger instances
+const loggers = Object.fromEntries(
+  LOG_TYPES.map(type => [type, createLogger(type)])
+) as Record<LogType, ReturnType<typeof createLogger>>
+
+const watchLogs = () => {
+  LOG_TYPES.forEach(type => {
+    const logFile = path.join(__dirname, '../../logs', `${type}.log`)
+
+    fs.watchFile(logFile, (curr, prev) => {
+      if (curr.size > prev.size) {
+        const stream = fs.createReadStream(logFile, { start: prev.size, end: curr.size })
+        stream.on('data', (chunk) => {
+          console.log(`[${type}] \n ${chunk.toString()}`)
+        })
+      }
+    })
+  })
+}
+
+export const { http: httpLogger, game: gameLogger, gameMaster: gameMasterLogger, app: appLogger } = loggers
+export { watchLogs }
\ No newline at end of file