Add better logging system

This commit is contained in:
√(noham)²
2026-06-19 16:02:39 +02:00
parent e0c93938be
commit 6a36db2e7a
9 changed files with 304 additions and 22 deletions

View File

@@ -1,6 +1,7 @@
import fs from 'node:fs'
import path from 'node:path'
import puppeteer from 'puppeteer'
import logger from './logger.js'
const EXTENSION_DIR = path.resolve('./extension/reader-view')
const MANIFEST_PATH = path.join(EXTENSION_DIR, 'manifest.json')
@@ -8,7 +9,7 @@ const READABILITY_PATH = path.join(EXTENSION_DIR, 'data/inject/Readability.js')
export function checkExtension () {
if (!fs.existsSync(MANIFEST_PATH)) {
console.error(
logger.error(
`Extension not found at: ${EXTENSION_DIR}\n` +
'Please extract the extension first:\n' +
' mkdir -p extension/reader-view\n' +
@@ -17,7 +18,7 @@ export function checkExtension () {
process.exit(1)
}
if (!fs.existsSync(READABILITY_PATH)) {
console.error(
logger.error(
`Readability.js not found at: ${READABILITY_PATH}\n` +
'The extension may be incomplete. Please re-extract it.'
)
@@ -34,7 +35,7 @@ export function getExtensionDir () {
}
export async function launchBrowser () {
console.log(`Launching browser with extension: ${EXTENSION_DIR}`)
logger.debug(`Launching browser with extension: ${EXTENSION_DIR}`)
const browser = await puppeteer.launch({
headless: true,
ignoreDefaultArgs: [
@@ -67,6 +68,6 @@ export async function discoverExtensionId (browser) {
if (!extId) {
throw new Error('Could not discover Reader View extension ID')
}
console.log(`Discovered extension ID: ${extId}`)
logger.debug(`Discovered extension ID: ${extId}`)
return extId
}

View File

@@ -27,6 +27,10 @@ program
'-o, --output <path>',
'output file path (default: ./output/<title>.pdf)'
)
.option(
'-l, --log-level <level>',
'logging level (fatal, error, warn, info, debug)'
)
.addHelpText(
'after',
`

View File

@@ -1,12 +1,13 @@
import fs from 'node:fs'
import path from 'node:path'
import logger from './logger.js'
export function loadPreferences (prefsPath) {
if (!prefsPath || !fs.existsSync(prefsPath)) return {}
try {
return JSON.parse(fs.readFileSync(prefsPath, 'utf-8'))
} catch (e) {
console.warn(`Warning: could not parse preferences file: ${prefsPath}`)
logger.warn(`Warning: could not parse preferences file: ${prefsPath}`)
return {}
}
}

View File

@@ -2,6 +2,7 @@ import process from 'node:process'
import path from 'node:path'
import { parseArgs, VALID_THEMES } from './cli.js'
import { loadPreferences, readCustomCss } from './config.js'
import logger from './logger.js'
import {
checkExtension,
launchBrowser,
@@ -37,20 +38,20 @@ async function main () {
const theme = opts.theme || preferences.mode || 'light'
if (!VALID_THEMES.includes(theme)) {
console.error(
logger.error(
`Invalid theme "${theme}". Valid themes: ${VALID_THEMES.join(', ')}`
)
process.exit(1)
}
preferences.mode = theme
console.log(`Theme: ${theme}`)
logger.info(`Theme: ${theme}`)
let customCss = null
if (opts.css) {
customCss = readCustomCss(path.resolve(opts.css))
if (customCss !== null) {
preferences['user-css'] = customCss
console.log(`Custom CSS loaded: ${path.resolve(opts.css)}`)
logger.info(`Custom CSS loaded: ${path.resolve(opts.css)}`)
}
}
@@ -59,7 +60,7 @@ async function main () {
try {
const extId = await discoverExtensionId(browser)
console.log(`Fetching article: ${url}`)
logger.info(`Fetching article: ${url}`)
const articlePage = await browser.newPage()
await articlePage.goto(url, { waitUntil: 'networkidle0', timeout: 30000 })
const article = await extractArticle(articlePage, getReadabilityPath())
@@ -83,7 +84,7 @@ async function main () {
'?id=1',
`&url=${encodeURIComponent(url)}`
].join('')
console.log(`Opening Reader View: ${readerUrl}`)
logger.debug(`Opening Reader View: ${readerUrl}`)
const readerPage = await browser.newPage()
await readerPage.goto(readerUrl, { waitUntil: 'load', timeout: 30000 })
@@ -109,11 +110,11 @@ async function main () {
await pdfPage.close()
} finally {
await browser.close()
console.log('Browser closed.')
logger.info('Browser closed.')
}
}
main().catch((err) => {
console.error('Fatal error:', err)
logger.error(err)
process.exit(1)
})

22
src/logger.js Normal file
View File

@@ -0,0 +1,22 @@
import pino from 'pino'
function resolveLevel () {
if (process.env.LOG_LEVEL) return process.env.LOG_LEVEL
const idx = process.argv.indexOf('--log-level')
if (idx !== -1 && process.argv[idx + 1]) return process.argv[idx + 1]
return 'info'
}
const logger = pino({
level: resolveLevel(),
transport: {
target: 'pino-pretty',
options: {
colorize: true,
translateTime: 'HH:MM:ss',
ignore: 'pid,hostname'
}
}
})
export default logger

View File

@@ -1,10 +1,11 @@
import fs from 'node:fs'
import path from 'node:path'
import logger from './logger.js'
const HIGHLIGHT_CSS =
'<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/default.min.css">'
const HIGHLIGHT_JS =
'<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"><script><script>hljs.highlightAll();<script>'
'<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"><\/script><script>hljs.highlightAll();<\/script>'
export function getOutputFilename (title, outputDir) {
const safe = title
@@ -42,7 +43,7 @@ export function enhanceHtml (html, customCss) {
export async function generatePdf (page, html, outputPath) {
await page.setContent(html, { waitUntil: 'networkidle0' })
console.log(`Generating PDF: ${outputPath}`)
logger.info(`Generating PDF: ${outputPath}`)
await page.pdf({
path: outputPath,
format: 'A4',
@@ -54,5 +55,5 @@ export async function generatePdf (page, html, outputPath) {
right: '0mm'
}
})
console.log(`PDF saved: ${outputPath}`)
logger.info(`PDF saved: ${outputPath}`)
}

View File

@@ -1,4 +1,5 @@
import fs from 'node:fs'
import logger from './logger.js'
export async function extractArticle (page, readabilityPath) {
const readabilitySource = fs.readFileSync(readabilityPath, 'utf-8')
@@ -51,7 +52,7 @@ export async function extractArticle (page, readabilityPath) {
if (!article) {
throw new Error('Failed to extract article content with Readability')
}
console.log(
logger.info(
`Extracted article: ${article.title} (${article.length} chars, reading ${article.readingTimeMinsFast}-${article.readingTimeMinsSlow} min` +
(article.published_time ? `, ${article.published_time}` : '') +
')'
@@ -90,7 +91,7 @@ export async function storeArticle (extPage, extId, articleId, article) {
},
{ id: articleId, article }
)
console.log('Article stored in extension IndexedDB')
logger.debug('Article stored in extension IndexedDB')
}
export async function setExtensionPreferences (page, extId, prefs) {
@@ -105,11 +106,11 @@ export async function setExtensionPreferences (page, extId, prefs) {
})
})
}, prefs)
console.log(`Extension preferences set: ${Object.keys(prefs).length} key(s)`)
logger.debug(`Extension preferences set: ${Object.keys(prefs).length} key(s)`)
}
export async function waitForReaderView (page) {
console.log('Waiting for Reader View to render article...')
logger.debug('Waiting for Reader View to render article...')
await page.waitForFunction(
() => {
const title = document.title
@@ -126,7 +127,7 @@ export async function waitForReaderView (page) {
},
{ timeout: 60000 }
)
console.log('Article rendered.')
logger.info('Article rendered.')
}
export async function extractRenderedContent (page, baseUrl) {