Skip to content

Commit

Permalink
migrate remaining logs in test-utils/* (#589)
Browse files Browse the repository at this point in the history
* migrate remaining logs

* nit

* err -> error
  • Loading branch information
miriambudayr authored Jul 3, 2024
1 parent 09609e9 commit fe9b225
Show file tree
Hide file tree
Showing 14 changed files with 155 additions and 127 deletions.
31 changes: 21 additions & 10 deletions packages/test-utils/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import fetch from "node-fetch";
import dbg from "debug";
import { warn } from "./logging";
import { logger } from "@replay-cli/shared/logger";
import { getErrorMessage } from "./legacy-cli/error";

const debug = dbg("replay:test-utils:config");
async function queryGraphqlEndpoint(apiKey: string, name: string, query: string, variables = {}) {
logger.info("QueryGraphqlEndpoint:Started", { name });

async function query(apiKey: string, name: string, query: string, variables = {}) {
const options = {
method: "POST",
headers: {
Expand All @@ -19,16 +20,19 @@ async function query(apiKey: string, name: string, query: string, variables = {}
};

const server = process.env.REPLAY_API_SERVER || "https://api.replay.io";
debug("Querying %s graphql endpoint", server);
logger.info("QueryGraphqlEndpoint", { server, name });

const result = await fetch(`${server}/v1/graphql`, options);
const json: any = await result.json();

logger.info("QueryGraphqlEndpoint:Succeeded", { server, name });

return json;
}

async function fetchWorkspaceConfig(apiKey: string) {
try {
const json = await query(
const json = await queryGraphqlEndpoint(
apiKey,
"GetWorkspaceConfig",
`
Expand All @@ -49,24 +53,31 @@ async function fetchWorkspaceConfig(apiKey: string) {
);

if (json.errors) {
debug("GraphQL failed: %s", json.errors);
const errorMessages = json.errors.map(getErrorMessage);
logger.error("FetchWorkspaceConfig:GraphqlFailed", { errorMessages });
throw new Error(json.errors[0].message || "Unexpected error");
}

const edges = json.data?.auth.workspaces.edges;
if (!edges || edges.length !== 1) {
debug("Failed to find workspace: %o", json.data);
logger.error("FetchWorkspaceConfig:FailedToFindWorkspace", {
hadEdges: !!edges,
edgesLength: edges?.length ?? null,
});

throw new Error("Failed to find a workspace for the given apiKey");
}

debug("Workspace settings: %o", edges[0].node.settings);
logger.info("FetchWorkspaceConfig", { workspaceSettings: edges[0].node.settings });

const features = edges[0].node.settings.features;

return {
env: features?.testSuites?.env || {},
};
} catch (e) {
warn("Failed to fetch test suite configuration; continuing with defaults", e);
} catch (error) {
warn("Failed to fetch test suite configuration; continuing with defaults", error);
logger.error("FetchWorkspaceConfig:Failed", { error });

return {
env: {},
Expand Down
35 changes: 23 additions & 12 deletions packages/test-utils/src/legacy-cli/auth.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,46 @@
import { readFile, writeFile } from "fs/promises";
import path from "path";
import dbg from "./debug";

import { Options } from "./types";
import { getDirectory } from "./utils";
import { logger } from "@replay-cli/shared/logger";

const debug = dbg("replay:cli:auth");
function parseTokenInfo(token: string) {
logger.info("ParseTokenInfo:Started");

function tokenInfo(token: string) {
const [_header, encPayload, _cypher] = token.split(".", 3);
if (typeof encPayload !== "string") {
debug("Token did not contain a valid payload: %s", maskToken(token));
logger.error("ParseTokenInfo:InvalidPayload", { maskedToken: maskToken(token) });
return null;
}

let payload;
try {
payload = JSON.parse(Buffer.from(encPayload, "base64").toString());
} catch (err) {
debug("Failed to decode token: %s %e", maskToken(token), err);
} catch (error) {
logger.error("ParseTokenInfo:DecodeFailed", {
maskedToken: maskToken(token),
error,
});
return null;
}

if (typeof payload !== "object") {
debug("Token payload was not an object");
logger.error("ParseTokenInfo:PayloadWasNotObject", {
maskedToken: maskToken(token),
payloadType: typeof payload,
});
return null;
}

return { payload };
}

function hasTokenExpired(token: string) {
const userInfo = tokenInfo(token);
logger.info("HasTokenExpired:Started");

const userInfo = parseTokenInfo(token);
const exp: number | undefined = userInfo?.payload?.exp;
debug("token expiration time: %d", exp ? exp * 1000 : 0);
logger.info("HasTokenExpired:GotExpirationTime", { expirationTime: exp ? exp * 1000 : 0 });

return exp != null && Date.now() - exp * 1000 > 0;
}
Expand All @@ -48,23 +55,27 @@ function getTokenPath(options: Options = {}) {
}

export async function readToken(options: Options = {}) {
logger.info("ReadToken:Started");

try {
const tokenPath = getTokenPath(options);
const tokenJson = await readFile(tokenPath, { encoding: "utf-8" });
const { token } = JSON.parse(tokenJson);

if (hasTokenExpired(token)) {
logger.info("ReadToken:TokenExpired", { tokenPath });
await writeFile(tokenPath, "{}");
return;
}

if (typeof token !== "string") {
logger.error("ReadToken:UnexpectedTokenValue", { tokenPath, token });
throw new Error("Unexpect token value: " + token);
}

return token;
} catch (e) {
debug("Failed to read/write token file: %o", e);
} catch (error) {
logger.error("ReadToken:Failed", { error });
return;
}
}
32 changes: 19 additions & 13 deletions packages/test-utils/src/legacy-cli/client.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import dbg from "./debug";
import WebSocket from "ws";
import { defer } from "./utils";
import { defer, maybeLogToConsole } from "./utils";
import { Agent } from "http";

const debug = dbg("replay:protocol");
import { logger } from "@replay-cli/shared/logger";

// Simple protocol client for use in writing standalone applications.

Expand Down Expand Up @@ -46,7 +44,7 @@ class ProtocolClient {
nextMessageId = 1;

constructor(address: string, callbacks: Callbacks, agent?: Agent) {
debug("Creating WebSocket for %s with %o", address, { agent });
logger.info("ProtocolClient:WillInitialize", { websocketAddress: address, agent });
this.socket = new WebSocket(address, {
agent: agent,
});
Expand All @@ -56,6 +54,7 @@ class ProtocolClient {
this.socket.on("close", callbacks.onClose);
this.socket.on("error", callbacks.onError);
this.socket.on("message", message => this.onMessage(message));
logger.info("ProtocolClient:DidInitialize", { websocketAddress: address, agent });
}

close() {
Expand Down Expand Up @@ -84,7 +83,8 @@ class ProtocolClient {
callback?: (err?: Error) => void
) {
const id = this.nextMessageId++;
debug("Sending command %s: %o", method, { id, params, sessionId });
logger.info("SendCommand:Started", { id, sessionId, method });

this.socket.send(
JSON.stringify({
id,
Expand All @@ -93,14 +93,19 @@ class ProtocolClient {
binary: data ? true : undefined,
sessionId,
}),
err => {
if (!err && data) {
error => {
if (!error && data) {
this.socket.send(data, callback);
} else {
if (err) {
debug("Received socket error: %s", err);
if (error) {
logger.error("SendCommand:ReceivedSocketError", {
id,
params,
sessionId,
error,
});
}
callback?.(err);
callback?.(error);
}
}
);
Expand All @@ -115,7 +120,8 @@ class ProtocolClient {

onMessage(contents: WebSocket.RawData) {
const msg = JSON.parse(String(contents));
debug("Received message %o", msg);
logger.info("OnMessage:ReceivedMessage", { msg });

if (msg.id) {
const { resolve, reject } = this.pendingMessages.get(msg.id);
this.pendingMessages.delete(msg.id);
Expand All @@ -129,7 +135,7 @@ class ProtocolClient {
} else if (this.eventListeners.has(msg.method)) {
this.eventListeners.get(msg.method)(msg.params);
} else {
console.log(`Received event without listener: ${msg.method}`);
logger.info("OnMessage:ReceivedEventWithoutListener", { msg });
}
}
}
Expand Down
37 changes: 3 additions & 34 deletions packages/test-utils/src/legacy-cli/debug.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import dbg from "debug";
import fs from "fs";
import util from "node:util";
import path from "path";
import { getDirectory } from "./utils";

const debugDebug = dbg("replay:cli:debug");
import { logger } from "@replay-cli/shared/logger";

const logDirPath = path.join(getDirectory(), "logs");
export let logPath = path.join(
Expand All @@ -19,38 +16,10 @@ export let logPath = path.join(
function init() {
try {
fs.mkdirSync(logDirPath, { recursive: true });
} catch (e) {
} catch (error) {
logPath = "";
debugDebug("Failed to create log directory %o", e);
logger.error("Init:FailedToCreateLogDirectory", { error });
}
}

let size = 0;
export default function debug(namespace: string, pathToLog: string = logPath) {
size = Math.max(size, namespace.length);
const d = dbg(namespace);

if (process.env.REPLAY_CLI_DISABLE_LOG) {
return d;
}

return (formatter: string, ...args: any[]) => {
d(formatter, ...args);

if (pathToLog) {
try {
const output = util
.format(formatter, ...args)
.split("\n")
.map((l, i) => (i === 0 ? l : "".padStart(size + 3, " ") + l))
.join("\n");
const prefix = `[${namespace}] `.padStart(size + 3, " ");
fs.appendFileSync(pathToLog, `${prefix}${output}\n`);
} catch (e) {
debugDebug("Failed to write log %o", e);
}
}
};
}

init();
16 changes: 7 additions & 9 deletions packages/test-utils/src/legacy-cli/launchdarkly.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import dbg from "./debug";
import { logger } from "@replay-cli/shared/logger";
import { initialize, LDClient, LDLogger } from "launchdarkly-node-client-sdk";

const debug = dbg("replay:launchdarkly");

type UserFeatureProfile = {
type: "user";
id: string;
Expand Down Expand Up @@ -48,8 +46,8 @@ class LaunchDarkly {
}
try {
await this.client.waitForInitialization();
} catch (e) {
debug("Failed to wait for LaunchDarkly initialization %j", e);
} catch (error) {
logger.error("LaunchDarklyIdentify:InitializationFailed", { error });
return;
}

Expand All @@ -73,8 +71,8 @@ class LaunchDarkly {
}
try {
await this.client.waitForInitialization();
} catch (e) {
debug("Failed to wait for LaunchDarkly initialization %j", e);
} catch (error) {
logger.error("LaunchDarklyVariant:WaitForInitializationFailed", { error });
return defaultValue;
}

Expand All @@ -88,8 +86,8 @@ class LaunchDarkly {
}
try {
await this.client.close();
} catch (e) {
debug("Failed to close LaunchDarkly client %j", e);
} catch (error) {
logger.error("LaunchDarklyClose:Failed", { error });
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/test-utils/src/legacy-cli/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
type UnstructuredMetadata,
} from "./types";
import { ReplayClient } from "./upload";
import { getDirectory, maybeLog as maybeLogToConsole } from "./utils";
import { getDirectory, maybeLogToConsole } from "./utils";
import { logger } from "@replay-cli/shared/logger";
export type { RecordingEntry } from "./types";
export { updateStatus } from "./updateStatus";
Expand Down
11 changes: 8 additions & 3 deletions packages/test-utils/src/legacy-cli/metadata/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { appendFileSync } from "fs";
import path from "path";

import { Options, UnstructuredMetadata } from "../types";
import { getDirectory, maybeLog } from "../utils";
import { getDirectory, maybeLogToConsole } from "../utils";

import * as test from "./test";
import * as source from "./source";
import { logger } from "@replay-cli/shared/logger";

// Each known metadata block should have a sanitizer that will check the contents before the upload
const handlers = {
Expand All @@ -29,11 +30,13 @@ async function sanitize(metadata: UnstructuredMetadata, opts: Options = {}) {
const value = metadata[key];

if (typeof value !== "object") {
maybeLog(
maybeLogToConsole(
opts.verbose,
`Ignoring metadata key "${key}". Expected an object but received ${typeof value}`
);

logger.info("SanitizeMetadata:UnexpectedKeyType", { key, keyType: typeof value });

continue;
}

Expand All @@ -46,10 +49,12 @@ async function sanitize(metadata: UnstructuredMetadata, opts: Options = {}) {
Object.assign(updated, validated);
} else {
// and warn when dropping all other types
maybeLog(
maybeLogToConsole(
opts.verbose,
`Ignoring metadata key "${key}". Custom metadata blocks must be prefixed by "x-". Try "x-${key}" instead.`
);

logger.info("SanitizeMetadata:IgnoringKey", { key });
}
}

Expand Down
Loading

0 comments on commit fe9b225

Please sign in to comment.