feat: add pino logger
This commit is contained in:
parent
c12dc1a6c7
commit
3015f13e0d
10 changed files with 195 additions and 47 deletions
|
|
@ -18,6 +18,7 @@ const recoverSessions = (process.env.RECOVER_SESSIONS || '').toLowerCase() === '
|
|||
const chromeBin = process.env.CHROME_BIN || null
|
||||
const headless = process.env.HEADLESS ? (process.env.HEADLESS).toLowerCase() === 'true' : true
|
||||
const releaseBrowserLock = process.env.RELEASE_BROWSER_LOCK ? (process.env.RELEASE_BROWSER_LOCK).toLowerCase() === 'true' : true
|
||||
const logLevel = process.env.LOGLEVEL || 'info'
|
||||
|
||||
module.exports = {
|
||||
sessionFolderPath,
|
||||
|
|
@ -35,5 +36,6 @@ module.exports = {
|
|||
recoverSessions,
|
||||
chromeBin,
|
||||
headless,
|
||||
releaseBrowserLock
|
||||
releaseBrowserLock,
|
||||
logLevel
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,11 +105,10 @@ const sendMessage = async (req, res) => {
|
|||
break
|
||||
}
|
||||
default:
|
||||
return sendErrorResponse(res, 400, 'contentType invalid, must be string, MessageMedia, MessageMediaFromURL, Location, Buttons, List, Contact or Poll')
|
||||
return sendErrorResponse(res, 400, 'invalid contentType')
|
||||
}
|
||||
res.json({ success: true, message: messageOut })
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
sendErrorResponse(res, 500, error.message)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ const fsp = require('fs').promises
|
|||
const qrcode = require('qrcode-terminal')
|
||||
const { sessionFolderPath } = require('../config')
|
||||
const { sendErrorResponse } = require('../utils')
|
||||
const { logger } = require('../logger')
|
||||
|
||||
/**
|
||||
* Responds to request with 'pong'
|
||||
|
|
@ -77,7 +78,7 @@ const localCallbackExample = async (req, res) => {
|
|||
}
|
||||
}
|
||||
*/
|
||||
console.log(error)
|
||||
logger.error(error, 'Failed to handle local callback')
|
||||
sendErrorResponse(res, 500, error.message)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
const qr = require('qr-image')
|
||||
const { setupSession, deleteSession, reloadSession, validateSession, flushSessions, sessions } = require('../sessions')
|
||||
const { sendErrorResponse, waitForNestedObject } = require('../utils')
|
||||
const { logger } = require('../logger')
|
||||
|
||||
/**
|
||||
* Starts a session for the given session ID.
|
||||
|
|
@ -16,8 +17,8 @@ const { sendErrorResponse, waitForNestedObject } = require('../utils')
|
|||
const startSession = async (req, res) => {
|
||||
// #swagger.summary = 'Start new session'
|
||||
// #swagger.description = 'Starts a session for the given session ID.'
|
||||
const sessionId = req.params.sessionId
|
||||
try {
|
||||
const sessionId = req.params.sessionId
|
||||
const setupSessionReturn = await setupSession(sessionId)
|
||||
if (!setupSessionReturn.success) {
|
||||
/* #swagger.responses[422] = {
|
||||
|
|
@ -45,7 +46,7 @@ const startSession = async (req, res) => {
|
|||
await waitForNestedObject(setupSessionReturn.client, 'pupPage')
|
||||
res.json({ success: true, message: setupSessionReturn.message })
|
||||
} catch (error) {
|
||||
console.log('startSession ERROR', error)
|
||||
logger.error({ sessionId, err: error }, 'Failed to start session')
|
||||
sendErrorResponse(res, 500, error.message)
|
||||
}
|
||||
}
|
||||
|
|
@ -64,8 +65,8 @@ const startSession = async (req, res) => {
|
|||
const statusSession = async (req, res) => {
|
||||
// #swagger.summary = 'Get session status'
|
||||
// #swagger.description = 'Status of the session with the given session ID.'
|
||||
const sessionId = req.params.sessionId
|
||||
try {
|
||||
const sessionId = req.params.sessionId
|
||||
const sessionData = await validateSession(sessionId)
|
||||
/* #swagger.responses[200] = {
|
||||
description: "Status of the session.",
|
||||
|
|
@ -78,7 +79,7 @@ const statusSession = async (req, res) => {
|
|||
*/
|
||||
res.json(sessionData)
|
||||
} catch (error) {
|
||||
console.log('statusSession ERROR', error)
|
||||
logger.error({ sessionId, err: error }, 'Failed to get session status')
|
||||
sendErrorResponse(res, 500, error.message)
|
||||
}
|
||||
}
|
||||
|
|
@ -97,8 +98,8 @@ const statusSession = async (req, res) => {
|
|||
const sessionQrCode = async (req, res) => {
|
||||
// #swagger.summary = 'Get session QR code'
|
||||
// #swagger.description = 'QR code of the session with the given session ID.'
|
||||
const sessionId = req.params.sessionId
|
||||
try {
|
||||
const sessionId = req.params.sessionId
|
||||
const session = sessions.get(sessionId)
|
||||
if (!session) {
|
||||
return res.json({ success: false, message: 'session_not_found' })
|
||||
|
|
@ -108,7 +109,7 @@ const sessionQrCode = async (req, res) => {
|
|||
}
|
||||
return res.json({ success: false, message: 'qr code not ready or already scanned' })
|
||||
} catch (error) {
|
||||
console.log('sessionQrCode ERROR', error)
|
||||
logger.error({ sessionId, err: error }, 'Failed to get session qr code')
|
||||
sendErrorResponse(res, 500, error.message)
|
||||
}
|
||||
}
|
||||
|
|
@ -127,8 +128,8 @@ const sessionQrCode = async (req, res) => {
|
|||
const sessionQrCodeImage = async (req, res) => {
|
||||
// #swagger.summary = 'Get session QR code as image'
|
||||
// #swagger.description = 'QR code as image of the session with the given session ID.'
|
||||
const sessionId = req.params.sessionId
|
||||
try {
|
||||
const sessionId = req.params.sessionId
|
||||
const session = sessions.get(sessionId)
|
||||
if (!session) {
|
||||
return res.json({ success: false, message: 'session_not_found' })
|
||||
|
|
@ -149,7 +150,7 @@ const sessionQrCodeImage = async (req, res) => {
|
|||
}
|
||||
return res.json({ success: false, message: 'qr code not ready or already scanned' })
|
||||
} catch (error) {
|
||||
console.log('sessionQrCodeImage ERROR', error)
|
||||
logger.error({ sessionId, err: error }, 'Failed to get session qr code image')
|
||||
sendErrorResponse(res, 500, error.message)
|
||||
}
|
||||
}
|
||||
|
|
@ -168,8 +169,8 @@ const sessionQrCodeImage = async (req, res) => {
|
|||
const restartSession = async (req, res) => {
|
||||
// #swagger.summary = 'Restart session'
|
||||
// #swagger.description = 'Restarts the session with the given session ID.'
|
||||
const sessionId = req.params.sessionId
|
||||
try {
|
||||
const sessionId = req.params.sessionId
|
||||
const validation = await validateSession(sessionId)
|
||||
if (validation.message === 'session_not_found') {
|
||||
return res.json(validation)
|
||||
|
|
@ -186,7 +187,7 @@ const restartSession = async (req, res) => {
|
|||
*/
|
||||
res.json({ success: true, message: 'Restarted successfully' })
|
||||
} catch (error) {
|
||||
console.log('restartSession ERROR', error)
|
||||
logger.error({ sessionId, err: error }, 'Failed to restart session')
|
||||
sendErrorResponse(res, 500, error.message)
|
||||
}
|
||||
}
|
||||
|
|
@ -205,8 +206,8 @@ const restartSession = async (req, res) => {
|
|||
const terminateSession = async (req, res) => {
|
||||
// #swagger.summary = 'Terminate session'
|
||||
// #swagger.description = 'Terminates the session with the given session ID.'
|
||||
const sessionId = req.params.sessionId
|
||||
try {
|
||||
const sessionId = req.params.sessionId
|
||||
const validation = await validateSession(sessionId)
|
||||
if (validation.message === 'session_not_found') {
|
||||
return res.json(validation)
|
||||
|
|
@ -223,7 +224,7 @@ const terminateSession = async (req, res) => {
|
|||
*/
|
||||
res.json({ success: true, message: 'Logged out successfully' })
|
||||
} catch (error) {
|
||||
console.log('terminateSession ERROR', error)
|
||||
logger.error({ sessionId, err: error }, 'Failed to terminate session')
|
||||
sendErrorResponse(res, 500, error.message)
|
||||
}
|
||||
}
|
||||
|
|
@ -254,7 +255,7 @@ const terminateInactiveSessions = async (req, res) => {
|
|||
*/
|
||||
res.json({ success: true, message: 'Flush completed successfully' })
|
||||
} catch (error) {
|
||||
console.log('terminateInactiveSessions ERROR', error)
|
||||
logger.error(error, 'Failed to terminate inactive sessions')
|
||||
sendErrorResponse(res, 500, error.message)
|
||||
}
|
||||
}
|
||||
|
|
@ -285,7 +286,7 @@ const terminateAllSessions = async (req, res) => {
|
|||
*/
|
||||
res.json({ success: true, message: 'Flush completed successfully' })
|
||||
} catch (error) {
|
||||
console.log('terminateAllSessions ERROR', error)
|
||||
logger.error(error, 'Failed to terminate all sessions')
|
||||
sendErrorResponse(res, 500, error.message)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
12
src/logger.js
Normal file
12
src/logger.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
const { logLevel } = require('./config')
|
||||
const pino = require('pino')
|
||||
|
||||
const logger = pino({
|
||||
level: logLevel
|
||||
}, pino.destination(1, { sync: false }))
|
||||
|
||||
logger.on('level-change', (lvl, val, prevLvl, prevVal) => {
|
||||
logger.info('%s (%d) was changed to %s (%d)', prevLvl, prevVal, lvl, val)
|
||||
})
|
||||
|
||||
module.exports = { logger }
|
||||
|
|
@ -3,7 +3,8 @@ const fs = require('fs')
|
|||
const path = require('path')
|
||||
const sessions = new Map()
|
||||
const { baseWebhookURL, sessionFolderPath, maxAttachmentSize, setMessagesAsSeen, webVersion, webVersionCacheType, recoverSessions, chromeBin, headless, releaseBrowserLock } = require('./config')
|
||||
const { triggerWebhook, waitForNestedObject, checkIfEventisEnabled } = require('./utils')
|
||||
const { triggerWebhook, waitForNestedObject, checkIfEventisEnabled, sendMessageSeenStatus } = require('./utils')
|
||||
const { logger } = require('./logger')
|
||||
|
||||
// Function to validate if the session is ready
|
||||
const validateSession = async (sessionId) => {
|
||||
|
|
@ -53,7 +54,7 @@ const validateSession = async (sessionId) => {
|
|||
returnData.message = 'session_connected'
|
||||
return returnData
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
logger.error({ sessionId, err: error }, 'Failed to validate session')
|
||||
return { success: false, state: null, message: error.message }
|
||||
}
|
||||
}
|
||||
|
|
@ -72,14 +73,13 @@ const restoreSessions = () => {
|
|||
const match = file.match(/^session-(.+)$/)
|
||||
if (match) {
|
||||
const sessionId = match[1]
|
||||
console.log('existing session detected', sessionId)
|
||||
logger.warn({ sessionId }, 'existing session detected')
|
||||
await setupSession(sessionId)
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
console.error('Failed to restore sessions:', error)
|
||||
logger.error(error, 'Failed to restore sessions')
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ const setupSession = async (sessionId) => {
|
|||
const singletonLockPath = path.resolve(path.join(sessionFolderPath, `session-${sessionId}`, 'SingletonLock'))
|
||||
const singletonLockExists = await fs.promises.lstat(singletonLockPath).then(() => true).catch(() => false)
|
||||
if (singletonLockExists) {
|
||||
console.log('Browser lock file exists, removing ', sessionId)
|
||||
logger.warn({ sessionId }, 'Browser lock file exists, removing')
|
||||
await fs.promises.unlink(singletonLockPath)
|
||||
}
|
||||
}
|
||||
|
|
@ -139,7 +139,7 @@ const setupSession = async (sessionId) => {
|
|||
try {
|
||||
await client.initialize()
|
||||
} catch (error) {
|
||||
console.log('Initialize error:', error.message)
|
||||
logger.error({ sessionId, err: error }, 'Initialize error')
|
||||
throw error
|
||||
}
|
||||
|
||||
|
|
@ -166,12 +166,12 @@ const initializeEvents = (client, sessionId) => {
|
|||
}
|
||||
client.pupPage.once('close', function () {
|
||||
// emitted when the page closes
|
||||
console.log(`Browser page closed for ${sessionId}. Restoring`)
|
||||
logger.warn({ sessionId }, 'Browser page closed. Restoring')
|
||||
restartSession(sessionId)
|
||||
})
|
||||
client.pupPage.once('error', function () {
|
||||
// emitted when the page crashes
|
||||
console.log(`Error occurred on browser page for ${sessionId}. Restoring`)
|
||||
logger.warn({ sessionId }, 'Error occurred on browser page. Restoring')
|
||||
restartSession(sessionId)
|
||||
})
|
||||
}).catch(e => { })
|
||||
|
|
@ -270,14 +270,13 @@ const initializeEvents = (client, sessionId) => {
|
|||
checkIfEventisEnabled('media').then(_ => {
|
||||
message.downloadMedia().then(messageMedia => {
|
||||
triggerWebhook(sessionWebhook, sessionId, 'media', { messageMedia, message })
|
||||
}).catch(e => {
|
||||
console.log('Download media error:', e.message)
|
||||
}).catch(error => {
|
||||
logger.error({ sessionId, err: error }, 'Failed to download media')
|
||||
})
|
||||
})
|
||||
}
|
||||
if (setMessagesAsSeen) {
|
||||
const chat = await message.getChat()
|
||||
chat.sendSeen()
|
||||
sendMessageSeenStatus(message)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
@ -287,8 +286,7 @@ const initializeEvents = (client, sessionId) => {
|
|||
client.on('message_ack', async (message, ack) => {
|
||||
triggerWebhook(sessionWebhook, sessionId, 'message_ack', { message, ack })
|
||||
if (setMessagesAsSeen) {
|
||||
const chat = await message.getChat()
|
||||
chat.sendSeen()
|
||||
sendMessageSeenStatus(message)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
@ -298,8 +296,7 @@ const initializeEvents = (client, sessionId) => {
|
|||
client.on('message_create', async (message) => {
|
||||
triggerWebhook(sessionWebhook, sessionId, 'message_create', { message })
|
||||
if (setMessagesAsSeen) {
|
||||
const chat = await message.getChat()
|
||||
chat.sendSeen()
|
||||
sendMessageSeenStatus(message)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
@ -407,7 +404,7 @@ const deleteSessionFolder = async (sessionId) => {
|
|||
}
|
||||
await fs.promises.rm(resolvedTargetDirPath, { recursive: true, force: true })
|
||||
} catch (error) {
|
||||
console.log('Folder deletion error', error)
|
||||
logger.error({ sessionId, err: error }, 'Folder deletion error')
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
|
@ -437,7 +434,7 @@ const reloadSession = async (sessionId) => {
|
|||
sessions.delete(sessionId)
|
||||
await setupSession(sessionId)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
logger.error({ sessionId, err: error }, 'Failed to reload session')
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
|
@ -452,11 +449,11 @@ const deleteSession = async (sessionId, validation) => {
|
|||
client.pupPage?.removeAllListeners('error')
|
||||
if (validation.success) {
|
||||
// Client Connected, request logout
|
||||
console.log(`Logging out session ${sessionId}`)
|
||||
logger.info({ sessionId }, 'Logging out session')
|
||||
await client.logout()
|
||||
} else if (validation.message === 'session_not_connected') {
|
||||
// Client not Connected, request destroy
|
||||
console.log(`Destroying session ${sessionId}`)
|
||||
logger.info({ sessionId }, 'Destroying session')
|
||||
await client.destroy()
|
||||
}
|
||||
// Wait 10 secs for client.pupBrowser to be disconnected before deleting the folder
|
||||
|
|
@ -468,7 +465,7 @@ const deleteSession = async (sessionId, validation) => {
|
|||
await deleteSessionFolder(sessionId)
|
||||
sessions.delete(sessionId)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
logger.error({ sessionId, err: error }, 'Failed to delete session')
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
|
@ -491,7 +488,7 @@ const flushSessions = async (deleteOnlyInactive) => {
|
|||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
logger.error(error, 'Failed to flush sessions')
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
|
|
|||
20
src/utils.js
20
src/utils.js
|
|
@ -1,10 +1,12 @@
|
|||
const axios = require('axios')
|
||||
const { globalApiKey, disabledCallbacks } = require('./config')
|
||||
const { logger } = require('./logger')
|
||||
|
||||
// Trigger webhook endpoint
|
||||
const triggerWebhook = (webhookURL, sessionId, dataType, data) => {
|
||||
axios.post(webhookURL, { dataType, data, sessionId }, { headers: { 'x-api-key': globalApiKey } })
|
||||
.catch(error => console.error('Failed to send new message webhook:', sessionId, dataType, error.message, data || ''))
|
||||
.then(() => logger.debug({ sessionId, dataType, data: data || '' }, `New webhook message sent to ${webhookURL}`))
|
||||
.catch(error => logger.error({ sessionId, dataType, err: error, data: data || '' }, `Failed to send new webhook message to ${webhookURL}`))
|
||||
}
|
||||
|
||||
// Function to send a response with error status and message
|
||||
|
|
@ -23,7 +25,7 @@ const waitForNestedObject = (rootObj, nestedPath, maxWaitTime = 10000, interval
|
|||
resolve()
|
||||
} else if (Date.now() - start > maxWaitTime) {
|
||||
// Maximum wait time exceeded, reject the promise
|
||||
console.log('Timed out waiting for nested object')
|
||||
logger.error('Timed out waiting for nested object')
|
||||
reject(new Error('Timeout waiting for nested object'))
|
||||
} else {
|
||||
// Nested object not yet created, continue waiting
|
||||
|
|
@ -35,12 +37,22 @@ const waitForNestedObject = (rootObj, nestedPath, maxWaitTime = 10000, interval
|
|||
}
|
||||
|
||||
const checkIfEventisEnabled = (event) => {
|
||||
return new Promise((resolve, reject) => { if (!disabledCallbacks.includes(event)) { resolve() } })
|
||||
return new Promise((resolve) => { if (!disabledCallbacks.includes(event)) { resolve() } })
|
||||
}
|
||||
|
||||
const sendMessageSeenStatus = async (message) => {
|
||||
try {
|
||||
const chat = await message.getChat()
|
||||
await chat.sendSeen()
|
||||
} catch (error) {
|
||||
logger.error(error, 'Failed to send seen status')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
triggerWebhook,
|
||||
sendErrorResponse,
|
||||
waitForNestedObject,
|
||||
checkIfEventisEnabled
|
||||
checkIfEventisEnabled,
|
||||
sendMessageSeenStatus
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue