diff --git a/islands/KMenu/commands/create_article.ts b/islands/KMenu/commands/create_article.ts index ab984fe..afbd920 100644 --- a/islands/KMenu/commands/create_article.ts +++ b/islands/KMenu/commands/create_article.ts @@ -22,7 +22,6 @@ export const createNewArticle: MenuEntry = { state.activeState.value = "loading"; fetchStream("/api/articles/create?url=" + value, (chunk) => { - console.log({ chunk: chunk.split("\n") }); if (chunk.startsWith("id:")) { state.loadingText.value = "Finished"; setTimeout(() => { diff --git a/islands/KMenu/commands/create_movie.ts b/islands/KMenu/commands/create_movie.ts index 1d308fb..0af2a70 100644 --- a/islands/KMenu/commands/create_movie.ts +++ b/islands/KMenu/commands/create_movie.ts @@ -32,7 +32,6 @@ export const createNewMovie: MenuEntry = { let currentQuery: string; const search = debounce(async function search(query: string) { currentQuery = query; - console.log({ query }); if (query.length < 2) { return; } diff --git a/lib/cache/cache.ts b/lib/cache/cache.ts index 049a17d..31afaf4 100644 --- a/lib/cache/cache.ts +++ b/lib/cache/cache.ts @@ -5,11 +5,14 @@ import { RedisConnectOptions, RedisValue, } from "https://deno.land/x/redis@v0.31.0/mod.ts"; +import { createLogger } from "@lib/log.ts"; const REDIS_HOST = Deno.env.get("REDIS_HOST"); const REDIS_PASS = Deno.env.get("REDIS_PASS") || ""; const REDIS_PORT = Deno.env.get("REDIS_PORT"); +const log = createLogger("cache"); + async function createCache(): Promise { if (REDIS_HOST) { const conf: RedisConnectOptions = { @@ -22,10 +25,10 @@ async function createCache(): Promise { } try { const client = await connect(conf); - console.log("[redis] connected"); + log.info("redis connected"); return client; } catch (_err) { - console.log("[cache] cant connect to redis, falling back to mock"); + log.info("cant connect to redis, falling back to mock"); } } @@ -94,7 +97,7 @@ export async function set( content: T, options?: RedisOptions, ) { - console.log("[cache] storing ", { id }); + log.debug("storing ", { id }); const res = await cache.set(id, content); if (options?.expires) { await expire(id, options.expires); diff --git a/lib/cache/image.ts b/lib/cache/image.ts index d1ffced..58fa7a9 100644 --- a/lib/cache/image.ts +++ b/lib/cache/image.ts @@ -1,6 +1,7 @@ import { hash } from "@lib/string.ts"; import * as cache from "@lib/cache/cache.ts"; import { ImageMagick } from "https://deno.land/x/imagemagick_deno@0.0.25/mod.ts"; +import { createLogger } from "@lib/log.ts"; type ImageCacheOptions = { url: string; @@ -10,6 +11,7 @@ type ImageCacheOptions = { }; const CACHE_KEY = "images"; +const log = createLogger("cache/image"); function getCacheKey({ url: _url, width, height }: ImageCacheOptions) { const url = new URL(_url); @@ -63,7 +65,7 @@ export async function setImage( const imageCorrect = await verifyImage(clone); if (!imageCorrect) { - console.log("[cache/image] failed to store image", { url }); + log.info("failed to store image", { url }); return; } diff --git a/lib/documents.ts b/lib/documents.ts index d6a43f1..42793aa 100644 --- a/lib/documents.ts +++ b/lib/documents.ts @@ -11,6 +11,7 @@ import remarkFrontmatter, { import * as cache from "@lib/cache/documents.ts"; import { SILVERBULLET_SERVER } from "@lib/env.ts"; import { fixRenderedMarkdown } from "@lib/helpers.ts"; +import { createLogger } from "@lib/log.ts"; export type Document = { name: string; @@ -20,13 +21,15 @@ export type Document = { perm: string; }; +const log = createLogger("documents"); + export async function getDocuments(): Promise { const cachedDocuments = await cache.getDocuments(); if (cachedDocuments) return cachedDocuments; const headers = new Headers(); headers.append("Accept", "application/json"); - console.log("[documents] fetching all documents"); + log.debug("fetching all documents"); const response = await fetch(`${SILVERBULLET_SERVER}/index.json`, { headers: headers, }); @@ -48,7 +51,7 @@ export function createDocument( headers.append("Content-Type", mediaType); } - console.log("[documents] creating document", { name }); + log.info("creating document", { name }); return fetch(SILVERBULLET_SERVER + "/" + name, { body: content, @@ -61,7 +64,7 @@ export async function getDocument(name: string): Promise { const cachedDocument = await cache.getDocument(name); if (cachedDocument) return cachedDocument; - console.log("[documents] fetching document", { name }); + log.debug("fetching document", { name }); const response = await fetch(SILVERBULLET_SERVER + "/" + name); const text = await response.text(); diff --git a/lib/log.ts b/lib/log.ts new file mode 100644 index 0000000..acfdecb --- /dev/null +++ b/lib/log.ts @@ -0,0 +1,53 @@ +enum LOG_LEVEL { + DEBUG, + INFO, + WARN, + ERROR, +} +let longestScope = 0; +let logLevel = LOG_LEVEL.WARN; + +export function setLogLevel(level: LOG_LEVEL) { + logLevel = level; +} + +const getPrefix = (scope: string) => `[${scope.padEnd(longestScope, " ")}]`; + +type LoggerOptions = { + enabled?: boolean; +}; + +export function createLogger(scope: string, _options?: LoggerOptions) { + longestScope = Math.max(scope.length, longestScope); + + function debug(...data: unknown[]) { + if (logLevel !== LOG_LEVEL.DEBUG) return; + console.debug(getPrefix(scope), ...data); + } + + function info(...data: unknown[]) { + if (logLevel !== LOG_LEVEL.DEBUG && logLevel !== LOG_LEVEL.INFO) return; + console.info(getPrefix(scope), ...data); + } + + function warn(...data: unknown[]) { + if ( + logLevel !== LOG_LEVEL.DEBUG && logLevel !== LOG_LEVEL.INFO && + logLevel !== LOG_LEVEL.WARN + ) return; + console.warn(getPrefix(scope), ...data); + } + + function error(...data: unknown[]) { + console.error(getPrefix(scope), ...data); + } + + return { + debug, + info, + error, + warn, + }; +} + +const log = createLogger(""); diff --git a/lib/resource/articles.ts b/lib/resource/articles.ts index bd2bf54..c0ac2d7 100644 --- a/lib/resource/articles.ts +++ b/lib/resource/articles.ts @@ -100,7 +100,6 @@ function parseArticle(original: string, id: string): Article { export const getAllArticles = crud.readAll; export const getArticle = crud.read; export const createArticle = (article: Article) => { - console.log("creating article", { article }); const content = renderArticle(article); return crud.create(article.id, content); }; diff --git a/lib/resource/movies.ts b/lib/resource/movies.ts index c71434d..94705cd 100644 --- a/lib/resource/movies.ts +++ b/lib/resource/movies.ts @@ -103,7 +103,6 @@ const crud = createCrud({ export const getMovie = crud.read; export const getAllMovies = crud.readAll; export const createMovie = (movie: Movie) => { - console.log("creating movie", { movie }); const content = renderMovie(movie); return crud.create(movie.id, content); }; diff --git a/lib/typesense.ts b/lib/typesense.ts index 65c370e..d97e352 100644 --- a/lib/typesense.ts +++ b/lib/typesense.ts @@ -3,6 +3,9 @@ import { TYPESENSE_API_KEY, TYPESENSE_URL } from "@lib/env.ts"; import { getAllMovies } from "@lib/resource/movies.ts"; import { getAllRecipes } from "@lib/resource/recipes.ts"; import { getAllArticles } from "@lib/resource/articles.ts"; +import { createLogger } from "@lib/log.ts"; + +const log = createLogger("typesense"); function sanitizeStringForTypesense(input: string) { // Remove backslashes @@ -82,12 +85,12 @@ async function initializeTypesense() { ], default_sorting_field: "rating", // Default field for sorting }); - console.log('[typesense] created "resources" collection'); + log.info('created "resources" collection'); } else { - console.log('[typesense] collection "resources" already exists.'); + log.info('collection "resources" already exists.'); } } catch (error) { - console.error("[typesense] error initializing", error); + log.error("error initializing", error); } } @@ -143,9 +146,9 @@ async function synchronizeWithTypesense() { // ), // ); - console.log("Data synchronized with Typesense."); + log.info("data synchronized"); } catch (error) { - console.error("Error synchronizing data with Typesense:", error); + log.error("error synchronizing", error); } } diff --git a/routes/api/articles/create/index.ts b/routes/api/articles/create/index.ts index 5036c4a..a963352 100644 --- a/routes/api/articles/create/index.ts +++ b/routes/api/articles/create/index.ts @@ -9,10 +9,11 @@ import tds from "https://cdn.skypack.dev/turndown@7.1.1"; import { Article, createArticle } from "@lib/resource/articles.ts"; import { getYoutubeVideoDetails } from "@lib/youtube.ts"; import { extractYoutubeId, isYoutubeLink } from "@lib/string.ts"; +import { createLogger } from "@lib/log.ts"; const parser = new DOMParser(); -//service.use(gfm); +const log = createLogger("api/article"); async function processCreateArticle( { fetchUrl, streamResponse }: { @@ -20,7 +21,7 @@ async function processCreateArticle( streamResponse: ReturnType; }, ) { - console.log("[api/article] create article from url", { url: fetchUrl }); + log.info("create article from url", { url: fetchUrl }); streamResponse.enqueue("downloading article"); @@ -48,7 +49,7 @@ async function processCreateArticle( const result = readable.parse(); - console.log("[api/article] parsed ", { + log.debug("parsed", { url: fetchUrl, content: result.textContent, }); @@ -173,7 +174,7 @@ async function processCreateYoutubeVideo( streamResponse: ReturnType; }, ) { - console.log("[api/article] create youtube article from url", { + log.info("create youtube article from url", { url: fetchUrl, }); @@ -187,6 +188,7 @@ async function processCreateYoutubeVideo( const newId = await openai.shortenTitle(video.snippet.title); const newArticle: Article = { + type: "article", name: video.snippet.title, id: newId || video.snippet.title, content: video.snippet.description, @@ -227,18 +229,18 @@ export const handler: Handlers = { if (isYoutubeLink(fetchUrl)) { processCreateYoutubeVideo({ fetchUrl, streamResponse }).then( (article) => { - console.log({ article }); + log.debug("created article from youtube", { article }); }, ).catch((err) => { - console.log(err); + log.error(err); }).finally(() => { streamResponse.cancel(); }); } else { processCreateArticle({ fetchUrl, streamResponse }).then((article) => { - console.log({ article }); + log.debug("created article from link", { article }); }).catch((err) => { - console.log(err); + log.error(err); }).finally(() => { streamResponse.cancel(); }); diff --git a/routes/api/images/index.ts b/routes/api/images/index.ts index da413e4..ecc1d19 100644 --- a/routes/api/images/index.ts +++ b/routes/api/images/index.ts @@ -11,6 +11,7 @@ import * as cache from "@lib/cache/image.ts"; import { SILVERBULLET_SERVER } from "@lib/env.ts"; import { PromiseQueue } from "@lib/promise.ts"; import { BadRequestError } from "@lib/errors.ts"; +import { createLogger } from "@lib/log.ts"; await initialize(); @@ -19,8 +20,10 @@ type ImageParams = { height: number; }; +const log = createLogger("api/image"); + async function getRemoteImage(image: string) { - console.log("[api/image] fetching", { image }); + log.debug("[api/image] fetching", { image }); const sourceRes = await fetch(image); if (!sourceRes.ok) { return "Error retrieving image from URL."; @@ -107,7 +110,7 @@ const queue = new PromiseQueue(); async function processImage(imageUrl: string, params: ImageParams) { const remoteImage = await getRemoteImage(imageUrl); if (typeof remoteImage === "string") { - console.log("[api/image] ERROR " + remoteImage); + log.warn("error fetching ", { remoteImage }); throw new BadRequestError(); } @@ -117,7 +120,7 @@ async function processImage(imageUrl: string, params: ImageParams) { mode: "resize", }); - console.log("[api/image] resized image", { + log.debug("resized image", { imageUrl, length: modifiedImage.length, }); @@ -144,14 +147,14 @@ const GET = async ( height: params.height, }); if (cachedResponse) { - console.log("[api/image] cached: " + imageUrl); + log.debug("cached", { imageUrl }); return new Response(cachedResponse.buffer.slice(), { headers: { "Content-Type": cachedResponse.mediaType, }, }); } else { - console.log("[api/image] no image in cache"); + log.debug("no image in cache"); } const [resizedImage, mediaType] = await queue.enqueue(() => @@ -165,8 +168,7 @@ const GET = async ( mediaType: mediaType, }); - console.log("[api/image] not-cached: " + imageUrl); - console.log({ imageUrl, resizedImage }); + log.debug("not-cached", { imageUrl, resizedImage }); return new Response(new Uint8Array(resizedImage), { headers: { diff --git a/routes/api/query/index.ts b/routes/api/query/index.ts index d1360e5..1c4ed38 100644 --- a/routes/api/query/index.ts +++ b/routes/api/query/index.ts @@ -37,7 +37,6 @@ export const handler: Handlers = { const authors = url.searchParams?.get("author")?.split(","); if (authors?.length) { - console.log({ authors }); resources = resources.filter((r) => { return r?.meta?.author && authors.includes(r?.meta?.author); }); diff --git a/routes/api/tmdb/credits/[id].ts b/routes/api/tmdb/credits/[id].ts index b1cd795..438abf2 100644 --- a/routes/api/tmdb/credits/[id].ts +++ b/routes/api/tmdb/credits/[id].ts @@ -2,6 +2,7 @@ import { HandlerContext } from "$fresh/server.ts"; import { getMovieCredits } from "@lib/tmdb.ts"; import * as cache from "@lib/cache/cache.ts"; import { json } from "@lib/helpers.ts"; +import { createLogger } from "@lib/log.ts"; type CachedMovieCredits = { lastUpdated: number; @@ -10,6 +11,8 @@ type CachedMovieCredits = { const CACHE_INTERVAL = 1000 * 60 * 24 * 30; +const log = createLogger("api/tmdb"); + export const handler = async ( _req: Request, _ctx: HandlerContext, @@ -22,7 +25,7 @@ export const handler = async ( }); } - console.log("[api] getting movie credits"); + log.debug("getting movie credits"); const cacheId = `/movie/credits/${id}`; diff --git a/routes/articles/[name].tsx b/routes/articles/[name].tsx index 6fe7bf0..847e171 100644 --- a/routes/articles/[name].tsx +++ b/routes/articles/[name].tsx @@ -19,8 +19,6 @@ export default function Greet(props: PageProps
) { const { author = "", date = "" } = article.meta; - console.log({ tags: article.tags }); - return ( ${article.name}`}> ) { const { author = "", date = "" } = movie.meta; - console.log(movie.description); - return ( ${movie.name}`}>