From 1f048b195c7acb2bff37bad80744d9b619086cb3 Mon Sep 17 00:00:00 2001
From: Marco Castignoli <marco@castignoli.it>
Date: Wed, 28 Jun 2023 10:13:53 +0200
Subject: [PATCH 1/7] implement logging for LibSourcify

---
 packages/lib-sourcify/src/index.ts            |  5 ++
 .../lib-sourcify/src/lib/CheckedContract.ts   | 14 +++--
 packages/lib-sourcify/src/lib/logger.ts       | 58 +++++++++++++++++++
 src/server/server.ts                          | 28 +++++++++
 4 files changed, 99 insertions(+), 6 deletions(-)
 create mode 100644 packages/lib-sourcify/src/lib/logger.ts

diff --git a/packages/lib-sourcify/src/index.ts b/packages/lib-sourcify/src/index.ts
index d409f2d6b..7a7c0fa6e 100644
--- a/packages/lib-sourcify/src/index.ts
+++ b/packages/lib-sourcify/src/index.ts
@@ -1,5 +1,10 @@
+import { setLogger, setLevel, ILogger } from './lib/logger';
+
 export * from './lib/validation';
 export * from './lib/verification';
 export * from './lib/CheckedContract';
 export * from './lib/types';
 export * from './lib/solidityCompiler';
+export const setLibSourcifyLogger = setLogger;
+export const setLibSourcifyLoggerLevel = setLevel;
+export type ILibSourcifyLogger = ILogger;
diff --git a/packages/lib-sourcify/src/lib/CheckedContract.ts b/packages/lib-sourcify/src/lib/CheckedContract.ts
index b94b82cab..5267e46ad 100644
--- a/packages/lib-sourcify/src/lib/CheckedContract.ts
+++ b/packages/lib-sourcify/src/lib/CheckedContract.ts
@@ -17,6 +17,8 @@ import { storeByHash } from './validation';
 import { decode as decodeBytecode } from '@ethereum-sourcify/bytecode-utils';
 import { ipfsHash } from './hashFunctions/ipfsHash';
 import { swarmBzzr0Hash, swarmBzzr1Hash } from './hashFunctions/swarmHash';
+import { logError, logInfo, logWarn } from './logger';
+// I used this file as an example of how to use it
 
 // TODO: find a better place for these constants. Reminder: this sould work also in the browser
 const IPFS_PREFIX = 'dweb:/ipfs/';
@@ -338,14 +340,14 @@ export async function performFetch(
   hash?: string,
   fileName?: string
 ): Promise<string | null> {
-  console.log(`Fetching the file ${fileName} from ${url}...`);
+  logInfo(`Fetching the file ${fileName} from ${url}...`);
   const res = await fetchWithTimeout(url, { timeout: FETCH_TIMEOUT }).catch(
     (err) => {
       if (err.type === 'aborted')
-        console.log(
+        logWarn(
           `Fetching the file ${fileName} from ${url} timed out. Timeout: ${FETCH_TIMEOUT}ms`
         );
-      else console.log(err);
+      else logError(err);
     }
   );
 
@@ -353,14 +355,14 @@ export async function performFetch(
     if (res.status === 200) {
       const content = await res.text();
       if (hash && Web3.utils.keccak256(content) !== hash) {
-        console.log("The calculated and the provided hash don't match.");
+        logError("The calculated and the provided hash don't match.");
         return null;
       }
 
-      console.log(`Successfully fetched the file ${fileName}`);
+      logInfo(`Successfully fetched the file ${fileName}`);
       return content;
     } else {
-      console.log(
+      logError(
         `Fetching the file ${fileName} failed with status: ${res?.status}`
       );
       return null;
diff --git a/packages/lib-sourcify/src/lib/logger.ts b/packages/lib-sourcify/src/lib/logger.ts
new file mode 100644
index 000000000..cb21abc68
--- /dev/null
+++ b/packages/lib-sourcify/src/lib/logger.ts
@@ -0,0 +1,58 @@
+export interface ILogger {
+  logLevel: number;
+  log: (level: number, message: string) => void;
+  setLevel: (level: number) => void;
+}
+
+// Default logger behavior
+export const DefaultLogger: ILogger = {
+  logLevel: 1,
+  setLevel(level: number) {
+    this.logLevel = level;
+  },
+  log(level, msg) {
+    if (level <= this.logLevel) {
+      switch (level) {
+        case 1:
+          console.error(msg);
+          break;
+        case 2:
+          console.warn(msg);
+          break;
+        case 3:
+          console.info(msg);
+          break;
+        case 4:
+          console.debug(msg);
+          break;
+      }
+    }
+  },
+};
+
+// Logger variable that will be used throughout the application
+let AppLogger: ILogger = DefaultLogger;
+
+export function setLogger(logger: ILogger) {
+  AppLogger = logger;
+}
+
+export function setLevel(level: number) {
+  AppLogger.setLevel(level);
+}
+
+export function logError(message: string) {
+  AppLogger.log(1, message);
+}
+
+export function logWarn(message: string) {
+  AppLogger.log(2, message);
+}
+
+export function logInfo(message: string) {
+  AppLogger.log(3, message);
+}
+
+export function logDebug(message: string) {
+  AppLogger.log(3, message);
+}
diff --git a/src/server/server.ts b/src/server/server.ts
index 41a6fd29d..c637cce2d 100644
--- a/src/server/server.ts
+++ b/src/server/server.ts
@@ -28,11 +28,39 @@ import { resolveRefs } from "json-refs";
 import { initDeprecatedRoutes } from "./deprecated.routes";
 import { getAddress, isAddress } from "ethers/lib/utils";
 import { logger } from "../common/loggerLoki";
+import { setLibSourcifyLogger } from "@ethereum-sourcify/lib-sourcify";
 // eslint-disable-next-line @typescript-eslint/no-var-requires
 const fileUpload = require("express-fileupload");
 
 const MemoryStore = createMemoryStore(session);
 
+// here we override the standard LibSourcify's Logger with a custom one
+setLibSourcifyLogger({
+  // No need to set again the logger level because it's set here
+  logLevel: 4,
+  setLevel(level: number) {
+    this.logLevel = level;
+  },
+  log(level, msg) {
+    if (level <= this.logLevel) {
+      switch (level) {
+        case 1:
+          logger.error(msg);
+          break;
+        case 2:
+          logger.warn(msg);
+          break;
+        case 3:
+          logger.info(msg);
+          break;
+        case 4:
+          logger.debug(msg);
+          break;
+      }
+    }
+  },
+});
+
 export class Server {
   app: express.Application;
   repository = config.repository.path;

From 04441b9734b409191392e45c2ad58522dd23a404 Mon Sep 17 00:00:00 2001
From: Marco Castignoli <marco@castignoli.it>
Date: Wed, 28 Jun 2023 13:42:36 +0200
Subject: [PATCH 2/7] replace all console.log in lib-sourcify

---
 .../lib-sourcify/src/lib/CheckedContract.ts    |  7 +++++--
 .../lib-sourcify/src/lib/solidityCompiler.ts   | 18 +++++++++---------
 packages/lib-sourcify/src/lib/verification.ts  | 11 ++++++-----
 3 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/packages/lib-sourcify/src/lib/CheckedContract.ts b/packages/lib-sourcify/src/lib/CheckedContract.ts
index 5267e46ad..3556c99ef 100644
--- a/packages/lib-sourcify/src/lib/CheckedContract.ts
+++ b/packages/lib-sourcify/src/lib/CheckedContract.ts
@@ -18,7 +18,6 @@ import { decode as decodeBytecode } from '@ethereum-sourcify/bytecode-utils';
 import { ipfsHash } from './hashFunctions/ipfsHash';
 import { swarmBzzr0Hash, swarmBzzr1Hash } from './hashFunctions/swarmHash';
 import { logError, logInfo, logWarn } from './logger';
-// I used this file as an example of how to use it
 
 // TODO: find a better place for these constants. Reminder: this sould work also in the browser
 const IPFS_PREFIX = 'dweb:/ipfs/';
@@ -248,7 +247,11 @@ export class CheckedContract {
         .map((e: any) => e.formattedMessage);
 
       const error = new Error('Compiler error');
-      console.error(errorMessages);
+      logWarn(
+        `Compiler error in CheckedContract.recompile: \n${errorMessages.join(
+          '\n\t'
+        )}`
+      );
       throw error;
     }
 
diff --git a/packages/lib-sourcify/src/lib/solidityCompiler.ts b/packages/lib-sourcify/src/lib/solidityCompiler.ts
index ba26901a6..b900e47d6 100644
--- a/packages/lib-sourcify/src/lib/solidityCompiler.ts
+++ b/packages/lib-sourcify/src/lib/solidityCompiler.ts
@@ -5,6 +5,7 @@ import { spawnSync } from 'child_process';
 import { fetchWithTimeout } from './utils';
 import { StatusCodes } from 'http-status-codes';
 import { JsonInput, PathBuffer } from './types';
+import { logError, logInfo, logWarn } from './logger';
 // eslint-disable-next-line @typescript-eslint/no-var-requires
 const solc = require('solc');
 
@@ -47,7 +48,7 @@ export async function useCompiler(version: string, solcJsonInput: JsonInput) {
   if (solcPlatform) {
     solcPath = await getSolcExecutable(solcPlatform, version);
   }
-  console.time('Compilation time');
+  const startCompilation = Date.now();
   if (solcPath) {
     const shellOutputBuffer = spawnSync(solcPath, ['--standard-json'], {
       input: inputStringified,
@@ -68,7 +69,7 @@ export async function useCompiler(version: string, solcJsonInput: JsonInput) {
       error = new Error(RECOMPILATION_ERR_MSG);
     }
     if (error) {
-      console.error(error);
+      logWarn(error.message);
       throw error;
     }
     compiled = shellOutputBuffer.stdout.toString();
@@ -79,7 +80,8 @@ export async function useCompiler(version: string, solcJsonInput: JsonInput) {
     }
   }
 
-  console.timeEnd('Compilation time');
+  const endCompilation = Date.now();
+  logInfo(`Compilation time : ${endCompilation - startCompilation}`);
 
   if (!compiled) {
     throw new Error('Compilation failed. No output from the compiler.');
@@ -92,7 +94,7 @@ export async function useCompiler(version: string, solcJsonInput: JsonInput) {
     const error = new Error(
       'Compiler error:\n ' + JSON.stringify(errorMessages)
     );
-    console.error(error);
+    logError(error.message);
     throw error;
   }
   return compiledJSON;
@@ -150,7 +152,7 @@ export async function getSolcExecutable(
   }
   const success = await fetchAndSaveSolc(platform, solcPath, version, fileName);
   if (success && !validateSolcPath(solcPath)) {
-    console.log(`Cannot validate solc ${version}.`);
+    logError(`Cannot validate solc ${version}.`);
     return null;
   }
   return success ? solcPath : null;
@@ -168,7 +170,7 @@ function validateSolcPath(solcPath: string): boolean {
     spawned.stderr.toString() ||
     'Error running solc, are you on the right platoform? (e.g. x64 vs arm)';
 
-  console.log(error);
+  logWarn(error);
   return false;
 }
 
@@ -215,9 +217,7 @@ async function fetchAndSaveSolc(
 
     return true;
   } else {
-    console.log(
-      `Failed fetching solc ${version} from GitHub: ${githubSolcURI}`
-    );
+    logWarn(`Failed fetching solc ${version} from GitHub: ${githubSolcURI}`);
   }
 
   return false;
diff --git a/packages/lib-sourcify/src/lib/verification.ts b/packages/lib-sourcify/src/lib/verification.ts
index d7cc21e2e..38436ff21 100644
--- a/packages/lib-sourcify/src/lib/verification.ts
+++ b/packages/lib-sourcify/src/lib/verification.ts
@@ -30,6 +30,7 @@ import { getAddress, getContractAddress } from '@ethersproject/address';
 import semverSatisfies from 'semver/functions/satisfies';
 import { defaultAbiCoder as abiCoder, ParamType } from '@ethersproject/abi';
 import { AbiConstructor } from 'abitype';
+import { logInfo, logWarn } from './logger';
 
 const RPC_TIMEOUT = process.env.RPC_TIMEOUT
   ? parseInt(process.env.RPC_TIMEOUT)
@@ -47,7 +48,7 @@ export async function verifyDeployed(
     chainId: sourcifyChain.chainId.toString(),
     status: null,
   };
-  console.log(
+  logInfo(
     `Verifying contract ${
       checkedContract.name
     } at address ${address} on chain ${sourcifyChain.chainId.toString()}`
@@ -501,7 +502,7 @@ export async function getBytecode(
       return bytecode;
     } catch (err) {
       // Catch to try the next RPC
-      console.log(err);
+      logWarn((err as Error).message);
     }
   }
   throw new Error('None of the RPCs responded');
@@ -524,12 +525,12 @@ async function getTx(creatorTxHash: string, sourcifyChain: SourcifyChain) {
         rejectInMs(RPC_TIMEOUT, rpcURL),
       ])) as Transaction;
       if (tx) {
-        console.log(`Transaction ${creatorTxHash} fetched via ${rpcURL}`);
+        logInfo(`Transaction ${creatorTxHash} fetched via ${rpcURL}`);
         return tx;
       }
     } catch (err) {
       // Catch to try the next RPC
-      console.log(err);
+      logWarn((err as Error).message);
     }
   }
   throw new Error('None of the RPCs responded');
@@ -682,7 +683,7 @@ function doesContainMetadataHash(bytecode: string) {
     containsMetadata =
       !!decodedCBOR.ipfs || !!decodedCBOR['bzzr0'] || !!decodedCBOR['bzzr1'];
   } catch (e) {
-    console.log("Can't decode CBOR");
+    logInfo("Can't decode CBOR");
     containsMetadata = false;
   }
   return containsMetadata;

From 6070ebbb172c813a39d09b3730b2a1b8cf085f4c Mon Sep 17 00:00:00 2001
From: Marco Castignoli <marco@castignoli.it>
Date: Wed, 28 Jun 2023 15:56:16 +0200
Subject: [PATCH 3/7] add logging to lib-sourcify's readme

---
 packages/lib-sourcify/README.md         | 46 +++++++++++++++++++++++++
 packages/lib-sourcify/src/lib/logger.ts |  2 +-
 2 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/packages/lib-sourcify/README.md b/packages/lib-sourcify/README.md
index e143fa845..5aacfd7ca 100644
--- a/packages/lib-sourcify/README.md
+++ b/packages/lib-sourcify/README.md
@@ -104,3 +104,49 @@ const match = await verifyCreate2(
 console.log(match.chainId); // '0'. create2 matches return 0 as chainId
 console.log(match.status); // 'perfect'
 ```
+
+## Logging
+
+`lib-sourcify` has a basic logging system.
+
+You can specify the log level using the `setLibSourcifyLoggerLevel(level)` where:
+
+- `0` is nothing
+- `1` is errors _[default]_
+- `2` is warnings
+- `3` is infos
+- `4` is debug
+
+You can override the logger by calling `setLogger(logger: ILibSourcifyLogger)`. This is an example:
+
+```javascript
+const winston = require('winston');
+const logger = winston.createLogger({
+  // ...
+});
+
+setLibSourcifyLogger({
+  logLevel: 4,
+  setLevel(level: number) {
+    this.logLevel = level;
+  },
+  log(level, msg) {
+    if (level <= this.logLevel) {
+      switch (level) {
+        case 1:
+          logger.error(msg);
+          break;
+        case 2:
+          logger.warn(msg);
+          break;
+        case 3:
+          logger.info(msg);
+          break;
+        case 4:
+          logger.debug(msg);
+          break;
+      }
+    }
+  },
+});
+```
diff --git a/packages/lib-sourcify/src/lib/logger.ts b/packages/lib-sourcify/src/lib/logger.ts
index cb21abc68..c36bcbdf7 100644
--- a/packages/lib-sourcify/src/lib/logger.ts
+++ b/packages/lib-sourcify/src/lib/logger.ts
@@ -54,5 +54,5 @@ export function logInfo(message: string) {
 }
 
 export function logDebug(message: string) {
-  AppLogger.log(3, message);
+  AppLogger.log(4, message);
 }

From 700984eb021631d8da3957da906283b637e2777d Mon Sep 17 00:00:00 2001
From: Marco Castignoli <marco@castignoli.it>
Date: Wed, 28 Jun 2023 16:26:58 +0200
Subject: [PATCH 4/7] change log level to warn

---
 packages/lib-sourcify/src/lib/logger.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/lib-sourcify/src/lib/logger.ts b/packages/lib-sourcify/src/lib/logger.ts
index c36bcbdf7..9e2c36e85 100644
--- a/packages/lib-sourcify/src/lib/logger.ts
+++ b/packages/lib-sourcify/src/lib/logger.ts
@@ -6,7 +6,7 @@ export interface ILogger {
 
 // Default logger behavior
 export const DefaultLogger: ILogger = {
-  logLevel: 1,
+  logLevel: 2,
   setLevel(level: number) {
     this.logLevel = level;
   },

From 175f6418e57f632d1759aba0370d77881a6afec6 Mon Sep 17 00:00:00 2001
From: Marco Castignoli <marco@ethereum.org>
Date: Thu, 29 Jun 2023 16:45:35 +0200
Subject: [PATCH 5/7] Update packages/lib-sourcify/src/lib/solidityCompiler.ts
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Kaan Uzdoğan <kaanuzdogan@hotmail.com>
---
 packages/lib-sourcify/src/lib/solidityCompiler.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/lib-sourcify/src/lib/solidityCompiler.ts b/packages/lib-sourcify/src/lib/solidityCompiler.ts
index b900e47d6..e0eebf50c 100644
--- a/packages/lib-sourcify/src/lib/solidityCompiler.ts
+++ b/packages/lib-sourcify/src/lib/solidityCompiler.ts
@@ -81,7 +81,7 @@ export async function useCompiler(version: string, solcJsonInput: JsonInput) {
   }
 
   const endCompilation = Date.now();
-  logInfo(`Compilation time : ${endCompilation - startCompilation}`);
+  logInfo(`Compilation time : ${endCompilation - startCompilation} ms`);
 
   if (!compiled) {
     throw new Error('Compilation failed. No output from the compiler.');

From c94cef068e4efea942496cd5c8c20ef2ae55be10 Mon Sep 17 00:00:00 2001
From: Marco Castignoli <marco@ethereum.org>
Date: Thu, 29 Jun 2023 16:45:54 +0200
Subject: [PATCH 6/7] Update src/server/server.ts
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Kaan Uzdoğan <kaanuzdogan@hotmail.com>
---
 src/server/server.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/server/server.ts b/src/server/server.ts
index c637cce2d..af7194589 100644
--- a/src/server/server.ts
+++ b/src/server/server.ts
@@ -37,7 +37,7 @@ const MemoryStore = createMemoryStore(session);
 // here we override the standard LibSourcify's Logger with a custom one
 setLibSourcifyLogger({
   // No need to set again the logger level because it's set here
-  logLevel: 4,
+  logLevel: process.env.NODE_ENV === "production" ? 3 : 4,
   setLevel(level: number) {
     this.logLevel = level;
   },

From 889004c5417d4a0331f96f8dc5cde9b96e921355 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= <kaanuzdogan@hotmail.com>
Date: Fri, 30 Jun 2023 11:07:51 +0200
Subject: [PATCH 7/7] Fix default level in README

---
 packages/lib-sourcify/README.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/lib-sourcify/README.md b/packages/lib-sourcify/README.md
index 5aacfd7ca..9e27c8990 100644
--- a/packages/lib-sourcify/README.md
+++ b/packages/lib-sourcify/README.md
@@ -112,8 +112,8 @@ console.log(match.status); // 'perfect'
 You can specify the log level using the `setLibSourcifyLoggerLevel(level)` where:
 
 - `0` is nothing
-- `1` is errors _[default]_
-- `2` is warnings
+- `1` is errors
+- `2` is warnings _[default]_
 - `3` is infos
 - `4` is debug