[CORL-540] Logging improvements (#2565)

* fix: enhanced errors around story creation

* feat: enhanced child loggers

* feat: logging enhancements
This commit is contained in:
Wyatt Johnson
2019-09-18 13:07:42 -04:00
committed by Kim Gardner
parent 741739bc16
commit 64f102e6d4
39 changed files with 318 additions and 135 deletions
+1 -1
View File
@@ -74,7 +74,7 @@ if (persist) {
if (fs.existsSync(persist)) {
// Create the new filename.
const name = path.basename(program.src);
const generated = "./src/core/server/graph/tenant/persisted/__generated__";
const generated = "./src/core/server/graph/common/persisted/__generated__";
// Create the generated directory if it doesn't exist.
fs.ensureDirSync(generated);
+6
View File
@@ -44,6 +44,12 @@ export enum ERROR_CODES {
*/
TOKEN_NOT_FOUND = "TOKEN_NOT_FOUND",
/**
* DUPLICATE_STORY_ID is used when trying to create a Story with the same ID
* as another Story.
*/
DUPLICATE_STORY_ID = "DUPLICATE_STORY_ID",
/**
* DUPLICATE_STORY_URL is used when trying to create a Story with the same URL
* as another Story.
@@ -100,11 +100,14 @@ export const confirmRequestHandler = ({
await userIDLimiter.test(req, targetUserID);
const log = coral.logger.child({
targetUserID,
requestingUserID: requestingUser.id,
tenantID: tenant.id,
});
const log = coral.logger.child(
{
targetUserID,
requestingUserID: requestingUser.id,
tenantID: tenant.id,
},
true
);
// Lookup the user.
const targetUser = await retrieveUser(mongo, tenant.id, targetUserID);
@@ -77,10 +77,13 @@ export const forgotHandler = ({
// Limit based on the email address.
await emailLimiter.test(req, email);
const log = coral.logger.child({
email,
tenantID: tenant.id,
});
const log = coral.logger.child(
{
email,
tenantID: tenant.id,
},
true
);
// Lookup the user.
const user = await retrieveUserWithProfile(mongo, tenant.id, {
+2 -1
View File
@@ -36,7 +36,7 @@ export const graphQLHandler = ({
}
// Pull out some useful properties from Coral.
const { id, now, tenant, cache, logger } = req.coral;
const { id, now, tenant, cache, logger, persisted } = req.coral;
if (!cache) {
throw new Error("cache was not set");
@@ -52,6 +52,7 @@ export const graphQLHandler = ({
id,
now,
req,
persisted,
config,
tenant,
logger,
@@ -1,17 +1,22 @@
import { AppOptions } from "coral-server/app";
import { RawQueryNotAuthorized } from "coral-server/errors";
import { getPersistedQuery } from "coral-server/graph/tenant/persisted";
import { getPersistedQuery } from "coral-server/graph/common/persisted";
import { GQLUSER_ROLE } from "coral-server/graph/tenant/schema/__generated__/types";
import { RequestHandler } from "coral-server/types/express";
type PersistedQueryMiddlewareOptions = Pick<
AppOptions,
"config" | "persistedQueryCache" | "persistedQueriesRequired"
"persistedQueryCache" | "persistedQueriesRequired"
>;
const persistedQueryMiddleware = (
options: PersistedQueryMiddlewareOptions
): RequestHandler => async (req, res, next) => {
const persistedQueryMiddleware = ({
persistedQueriesRequired,
persistedQueryCache,
}: PersistedQueryMiddlewareOptions): RequestHandler => async (
req,
res,
next
) => {
try {
if (!req.coral) {
throw new Error("coral was not set");
@@ -25,12 +30,12 @@ const persistedQueryMiddleware = (
// Handle the payload if it is a persisted query.
const body = req.method === "GET" ? req.query : req.body;
const query = await getPersistedQuery(options.persistedQueryCache, body);
if (!query) {
const persisted = await getPersistedQuery(persistedQueryCache, body);
if (!persisted) {
// Check to see if this is from an ADMIN token which is allowed to run
// un-persisted queries.
if (
options.persistedQueriesRequired &&
persistedQueriesRequired &&
(!req.user || req.user.role !== GQLUSER_ROLE.ADMIN)
) {
throw new RawQueryNotAuthorized(
@@ -41,7 +46,11 @@ const persistedQueryMiddleware = (
} else {
// The query was found for this operation, replace the query with the one
// provided.
body.query = query.query;
body.query = persisted.query;
// Associate the persisted query with the request so it can be attached to
// the context.
req.coral.persisted = persisted;
}
return next();
+13 -4
View File
@@ -1,8 +1,11 @@
import { ErrorRequestHandler, RequestHandler } from "express";
import onFinished from "on-finished";
import now from "performance-now";
import logger from "coral-server/logger";
import {
ErrorRequestHandler,
RequestHandler,
} from "coral-server/types/express";
export const accessLogger: RequestHandler = (req, res, next) => {
const startTime = now();
@@ -14,10 +17,12 @@ export const accessLogger: RequestHandler = (req, res, next) => {
// Get some extra goodies from the request.
const userAgent = req.get("User-Agent");
// Grab the logger.
const log = req.coral ? req.coral.logger : logger;
// Log this out.
logger.info(
log.debug(
{
// traceID: req.id,
url: req.originalUrl || req.url,
method: req.method,
statusCode: res.statusCode,
@@ -32,7 +37,11 @@ export const accessLogger: RequestHandler = (req, res, next) => {
};
export const errorLogger: ErrorRequestHandler = (err, req, res, next) => {
logger.error({ err }, "http error");
// Grab the logger.
const log = req.coral ? req.coral.logger : logger;
// Log this out.
log.error({ err }, "http error");
next(err);
};
+8 -1
View File
@@ -26,7 +26,11 @@ export const tenantMiddleware = ({
const now = new Date();
// Set Coral on the request.
req.coral = { id, now, logger: logger.child({ traceID: id }) };
req.coral = {
id,
now,
logger: logger.child({ context: "http", contextID: id }, true),
};
}
// Set the Coral Tenant Cache on the request.
@@ -47,6 +51,9 @@ export const tenantMiddleware = ({
return next(new TenantNotFoundError(req.hostname));
}
// Augment the logger with the tenantID.
req.coral.logger = req.coral.logger.child({ tenantID: tenant.id }, true);
// Attach the tenant to the request.
req.coral.tenant = tenant;
+3 -1
View File
@@ -39,7 +39,7 @@ const deleteScheduledAccounts: ScheduledJobCommand<Options> = async ({
}) => {
// For each of the tenant's, process their users notifications.
for await (const tenant of tenantCache) {
log = log.child({ tenantID: tenant.id });
log = log.child({ tenantID: tenant.id }, true);
while (true) {
const now = new Date();
@@ -77,6 +77,8 @@ const deleteScheduledAccounts: ScheduledJobCommand<Options> = async ({
},
},
});
} else {
log.info({ userID: user.id }, "user did not have an email address");
}
}
}
+8 -5
View File
@@ -21,10 +21,13 @@ export class ScheduledJob<T extends {} = {}> {
constructor(context: T, opts: Options<T>) {
this.context = context;
this.log = logger.child({
jobName: opts.name,
jobFrequency: opts.cronTime,
});
this.log = logger.child(
{
jobName: opts.name,
jobFrequency: opts.cronTime,
},
true
);
this.job = new CronJob({
cronTime: opts.cronTime,
onTick: this.command(opts.command),
@@ -36,7 +39,7 @@ export class ScheduledJob<T extends {} = {}> {
private command(command: ScheduledJobCommand<T>): CronCommand {
return async () => {
const log = this.log.child({ scheduledExecutionID: uuid.v1() });
const log = this.log.child({ scheduledExecutionID: uuid.v1() }, true);
log.debug("now starting scheduled job");
const start = now();
try {
+17 -2
View File
@@ -1,6 +1,7 @@
// tslint:disable:max-classes-per-file
import { FluentBundle } from "fluent/compat";
import { MongoError } from "mongodb";
import uuid from "uuid";
import { VError } from "verror";
@@ -280,9 +281,23 @@ export class EmailNotSetError extends CoralError {
}
}
export class DuplicateStoryIDError extends CoralError {
constructor(cause: MongoError, id: string, url?: string) {
super({
cause,
code: ERROR_CODES.DUPLICATE_STORY_ID,
context: { pvt: { id, url } },
});
}
}
export class DuplicateStoryURLError extends CoralError {
constructor(url: string) {
super({ code: ERROR_CODES.DUPLICATE_STORY_URL, context: { pvt: { url } } });
constructor(cause: MongoError, url: string, id?: string) {
super({
cause,
code: ERROR_CODES.DUPLICATE_STORY_URL,
context: { pvt: { id, url } },
});
}
}
+1
View File
@@ -6,6 +6,7 @@ export const ERROR_TRANSLATIONS: Record<ERROR_CODES, string> = {
COMMENT_NOT_FOUND: "error-commentNotFound",
COMMENTING_DISABLED: "error-commentingDisabled",
DUPLICATE_EMAIL: "error-duplicateEmail",
DUPLICATE_STORY_ID: "error-duplicateStoryID",
DUPLICATE_STORY_URL: "error-duplicateStoryURL",
DUPLICATE_USER: "error-duplicateUser",
EMAIL_ALREADY_SET: "error-emailAlreadySet",
+12 -4
View File
@@ -4,6 +4,7 @@ import uuid from "uuid";
import { LanguageCode } from "coral-common/helpers/i18n/locales";
import { Config } from "coral-server/config";
import logger, { Logger } from "coral-server/logger";
import { PersistedQuery } from "coral-server/models/queries";
import { User } from "coral-server/models/user";
import { I18n } from "coral-server/services/i18n";
import { AugmentedRedis } from "coral-server/services/redis";
@@ -18,6 +19,7 @@ export interface CommonContextOptions {
logger?: Logger;
lang?: LanguageCode;
disableCaching?: boolean;
persisted?: PersistedQuery;
config: Config;
i18n: I18n;
pubsub: RedisPubSub;
@@ -28,6 +30,7 @@ export interface CommonContextOptions {
export default class CommonContext {
public readonly user?: User;
public readonly req?: Request;
public readonly persisted?: PersistedQuery;
public readonly id: string;
public readonly config: Config;
public readonly i18n: I18n;
@@ -45,6 +48,7 @@ export default class CommonContext {
logger: log = logger,
user,
req,
persisted,
config,
i18n,
lang = i18n.getDefaultLang(),
@@ -54,13 +58,17 @@ export default class CommonContext {
disableCaching = false,
}: CommonContextOptions) {
this.id = id;
this.logger = log.child({
context: "graph",
contextID: id,
});
this.logger = log.child(
{
context: "graph",
contextID: id,
},
true
);
this.now = now;
this.user = user;
this.req = req;
this.persisted = persisted;
this.config = config;
this.i18n = i18n;
this.lang = lang;
@@ -7,7 +7,8 @@ import {
import now from "performance-now";
import CommonContext from "coral-server/graph/common/context";
import { getOperationMetadata } from "./helpers";
import { getOperationMetadata, getPersistedQueryMetadata } from "./helpers";
export function logError(ctx: CommonContext, err: GraphQLError) {
ctx.logger.error({ err }, "graphql query error");
@@ -16,12 +17,20 @@ export function logError(ctx: CommonContext, err: GraphQLError) {
export function logQuery(
ctx: CommonContext,
document: DocumentNode,
persisted = ctx.persisted,
responseTime?: number
) {
ctx.logger.debug(
ctx.logger.info(
{
responseTime,
...getOperationMetadata(document),
authenticated: ctx.user ? true : false,
...(persisted
? // A persisted query was provided, we can pull the operation metadata
// out from the persisted object.
getPersistedQueryMetadata(persisted)
: // A persisted query was not provided, parse the operation metadata
// out from the document.
getOperationMetadata(document)),
},
"graphql query"
);
@@ -44,6 +53,7 @@ export class LoggerExtension implements GraphQLExtension<CommonContext> {
logQuery(
o.executionArgs.contextValue,
o.executionArgs.document,
undefined,
responseTime
);
};
@@ -1,6 +1,26 @@
import { DocumentNode, OperationDefinitionNode } from "graphql";
import {
DocumentNode,
OperationDefinitionNode,
OperationTypeNode,
} from "graphql";
export function getOperationMetadata(doc: DocumentNode) {
import { PersistedQuery } from "coral-server/models/queries";
export interface OperationMetadata {
operationName: string;
operation: OperationTypeNode;
}
/**
* getOperationMetadata will extract the operation metadata from the document
* node.
*
* @param doc the document node that can be used to extract operation metadata
* from
*/
export const getOperationMetadata = (
doc: DocumentNode
): Partial<OperationMetadata> => {
if (doc.kind === "Document") {
const operationDefinition = doc.definitions.find(
({ kind }) => kind === "OperationDefinition"
@@ -19,4 +39,30 @@ export function getOperationMetadata(doc: DocumentNode) {
}
return {};
};
interface PersistedQueryOperationMetadata extends OperationMetadata {
persistedQueryID: string;
persistedQueryBundle: string;
persistedQueryVersion: string;
}
/**
* getPersistedQueryMetadata will remap the persisted query to the operation
* metadata.
*
* @param persisted persisted query to remap to operation metadata
*/
export const getPersistedQueryMetadata = ({
id: persistedQueryID,
operation,
operationName,
bundle: persistedQueryBundle,
version: persistedQueryVersion,
}: PersistedQuery): PersistedQueryOperationMetadata => ({
persistedQueryID,
persistedQueryBundle,
persistedQueryVersion,
operation,
operationName,
});
@@ -29,7 +29,7 @@ export async function getPersistedQuery(
// empty.
!(payload.query === "PERSISTED_QUERY" || payload.query === "")
) {
return null;
return undefined;
}
const query = await cache.get(payload.id);
+1 -1
View File
@@ -49,7 +49,7 @@ export default class TenantContext extends CommonContext {
super({
...options,
lang: tenant.locale,
logger: logger.child({ tenantID: tenant.id }),
logger: logger.child({ tenantID: tenant.id }, true),
});
this.tenant = tenant;
@@ -35,9 +35,10 @@ import {
logQuery,
} from "coral-server/graph/common/extensions";
import { getOperationMetadata } from "coral-server/graph/common/extensions/helpers";
import { getPersistedQuery } from "coral-server/graph/tenant/persisted";
import { getPersistedQuery } from "coral-server/graph/common/persisted";
import { GQLUSER_ROLE } from "coral-server/graph/tenant/schema/__generated__/types";
import logger from "coral-server/logger";
import { PersistedQuery } from "coral-server/models/queries";
import { hasStaffRole } from "coral-server/models/user/helpers";
import { extractTokenFromRequest } from "coral-server/services/jwt";
@@ -166,7 +167,10 @@ export function onConnect(options: OnConnectOptions): OnConnectFn {
export type FormatResponseOptions = Pick<AppOptions, "metrics">;
export function formatResponse({ metrics }: FormatResponseOptions) {
export function formatResponse(
{ metrics }: FormatResponseOptions,
persisted?: PersistedQuery
) {
return (
value: ExecutionResult,
{ context, query }: ExecutionParams<TenantContext>
@@ -177,7 +181,7 @@ export function formatResponse({ metrics }: FormatResponseOptions) {
}
// Log out the query.
logQuery(context, query);
logQuery(context, query, persisted);
// Increment the metrics if enabled.
if (metrics) {
@@ -217,15 +221,12 @@ export function onOperation(options: OnOperationOptions) {
message: OperationMessage,
params: ExecutionParams<TenantContext>
) => {
// Attach the response formatter.
params.formatResponse = formatResponse(options);
// Handle the payload if it is a persisted query.
const query = await getPersistedQuery(
const persisted = await getPersistedQuery(
options.persistedQueryCache,
message.payload
);
if (!query) {
if (!persisted) {
// Check to see if this is from an ADMIN token which is allowed to run
// un-persisted queries.
if (
@@ -241,9 +242,12 @@ export function onOperation(options: OnOperationOptions) {
} else {
// The query was found for this operation, replace the query with the one
// provided.
params.query = query.query;
params.query = persisted.query;
}
// Attach the response formatter.
params.formatResponse = formatResponse(options, persisted);
return params;
};
}
+6 -3
View File
@@ -19,9 +19,12 @@ type IndexCreationFunction<T> = (
export function createIndexFactory<T>(
collection: Collection<T>
): IndexCreationFunction<T> {
const log = logger.child({
collectionName: collection.collectionName,
});
const log = logger.child(
{
collectionName: collection.collectionName,
},
true
);
return async (
indexSpec: IndexSpecification<T>,
+2 -1
View File
@@ -1,3 +1,4 @@
import { OperationTypeNode } from "graphql";
import { Db } from "mongodb";
import {
@@ -9,7 +10,7 @@ const collection = createCollection<Readonly<PersistedQuery>>("queries");
export interface PersistedQuery {
id: string;
operation: string;
operation: OperationTypeNode;
operationName: string;
query: string;
bundle: string;
+34 -21
View File
@@ -3,7 +3,10 @@ import uuid from "uuid";
import { DeepPartial, Omit } from "coral-common/types";
import { dotize } from "coral-common/utils/dotize";
import { DuplicateStoryURLError } from "coral-server/errors";
import {
DuplicateStoryIDError,
DuplicateStoryURLError,
} from "coral-server/errors";
import {
GQLStoryMetadata,
GQLStorySettings,
@@ -120,14 +123,14 @@ export interface UpsertStoryInput {
export async function upsertStory(
mongo: Db,
tenantID: string,
{ id, url }: UpsertStoryInput,
{ id = uuid.v4(), url }: UpsertStoryInput,
now = new Date()
) {
// Create the story, optionally sourcing the id from the input, additionally
// porting in the tenantID.
const update: { $setOnInsert: Story } = {
$setOnInsert: {
id: id ? id : uuid.v4(),
id,
url,
tenantID,
createdAt: now,
@@ -140,25 +143,35 @@ export async function upsertStory(
},
};
// Perform the find and update operation to try and find and or create the
// story.
const result = await collection(mongo).findOneAndUpdate(
{
url,
tenantID,
},
update,
{
// Create the object if it doesn't already exist.
upsert: true,
try {
// Perform the find and update operation to try and find and or create the
// story.
const result = await collection(mongo).findOneAndUpdate(
{
url,
tenantID,
},
update,
{
// Create the object if it doesn't already exist.
upsert: true,
// False to return the updated document instead of the original
// document.
returnOriginal: false,
// False to return the updated document instead of the original
// document.
returnOriginal: false,
}
);
return result.value || null;
} catch (err) {
// Evaluate the error, if it is in regards to violating the unique index,
// then return a duplicate Story error.
if (err instanceof MongoError && err.code === 11000) {
throw new DuplicateStoryIDError(err, id, url);
}
);
return result.value || null;
throw err;
}
}
export interface FindStoryInput {
@@ -256,7 +269,7 @@ export async function createStory(
// Evaluate the error, if it is in regards to violating the unique index,
// then return a duplicate Story error.
if (err instanceof MongoError && err.code === 11000) {
throw new DuplicateStoryURLError(url);
throw new DuplicateStoryURLError(err, url, id);
}
throw err;
@@ -343,7 +356,7 @@ export async function updateStory(
// Evaluate the error, if it is in regards to violating the unique index,
// then return a duplicate Story error.
if (input.url && err instanceof MongoError && err.code === 11000) {
throw new DuplicateStoryURLError(input.url);
throw new DuplicateStoryURLError(err, input.url, id);
}
throw err;
+1 -1
View File
@@ -556,7 +556,7 @@ export async function insertUser(
await collection(mongo).insert(user);
} catch (err) {
// Evaluate the error, if it is in regards to violating the unique index,
// then return a duplicate Story error.
// then return a duplicate User error.
if (err instanceof MongoError && err.code === 11000) {
// Check if duplicate index was about the email.
if (err.errmsg && err.errmsg.includes("tenantID_1_email_1")) {
+2 -2
View File
@@ -21,7 +21,7 @@ export default class Task<T, U = any> {
jobOptions = {},
queue,
}: TaskOptions<T, U>) {
this.log = logger.child({ jobName });
this.log = logger.child({ jobName }, true);
this.queue = new Queue(jobName, queue);
this.options = {
jobName,
@@ -70,7 +70,7 @@ export default class Task<T, U = any> {
*/
public process() {
this.queue.process(async (job: Job<T>) => {
const log = this.log.child({ jobID: job.id });
const log = this.log.child({ jobID: job.id }, true);
log.trace("processing job from queue");
+7 -4
View File
@@ -38,10 +38,13 @@ export class MailerQueue {
}
public async add({ template, tenantID, message: { to } }: MailerInput) {
const log = logger.child({
jobName: JOB_NAME,
tenantID,
});
const log = logger.child(
{
jobName: JOB_NAME,
tenantID,
},
true
);
// All email templates require the tenant in order to insert the footer, so
// load it from the tenant cache here.
@@ -206,11 +206,14 @@ export const createJobProcessor = (options: MailProcessorOptions) => {
// Pull the data out of the validated model.
const { tenantID } = data;
const log = logger.child({
jobID: job.id,
jobName: JOB_NAME,
tenantID,
});
const log = logger.child(
{
jobID: job.id,
jobName: JOB_NAME,
tenantID,
},
true
);
// Get the referenced tenant so we know who to send it from.
const tenant = await tenantCache.retrieveByID(tenantID);
@@ -70,11 +70,14 @@ export const createJobProcessor = ({
const { tenantID, input } = job.data;
// Create a new logger to handle logging for this job.
const log = logger.child({
jobID: job.id,
jobName: JOB_NAME,
tenantID,
});
const log = logger.child(
{
jobID: job.id,
jobName: JOB_NAME,
tenantID,
},
true
);
log.debug("starting to handle a notify operation");
+10 -7
View File
@@ -24,13 +24,16 @@ const createJobProcessor = ({ mongo }: ScrapeProcessorOptions) => async (
// Pull out the job data.
const { storyID, storyURL, tenantID } = job.data;
const log = logger.child({
jobID: job.id,
jobName: JOB_NAME,
storyID,
storyURL,
tenantID,
});
const log = logger.child(
{
jobID: job.id,
jobName: JOB_NAME,
storyID,
storyURL,
tenantID,
},
true
);
// Mark the start time.
const startTime = now();
+16 -10
View File
@@ -68,13 +68,16 @@ export async function create(
now = new Date(),
req?: Request
) {
let log = logger.child({
authorID: author.id,
tenantID: tenant.id,
storyID: input.storyID,
parentID: input.parentID,
nudge,
});
let log = logger.child(
{
authorID: author.id,
tenantID: tenant.id,
storyID: input.storyID,
parentID: input.parentID,
nudge,
},
true
);
// TODO: (wyattjoh) perform rate limiting based on the user?
@@ -178,7 +181,10 @@ export async function create(
// Pull the revision out.
const revision = getLatestRevision(comment);
log = log.child({ commentID: comment.id, status, revisionID: revision.id });
log = log.child(
{ commentID: comment.id, status, revisionID: revision.id },
true
);
log.trace("comment created");
@@ -262,7 +268,7 @@ export async function edit(
now = new Date(),
req?: Request
) {
let log = logger.child({ commentID: input.id, tenantID: tenant.id });
let log = logger.child({ commentID: input.id, tenantID: tenant.id }, true);
// Get the comment that we're editing. This comment is considered stale,
// because it wasn't involved in the atomic transaction.
@@ -345,7 +351,7 @@ export async function edit(
// Pull the old/edited comments out of the edit result.
const { oldComment, editedComment, newRevision } = result;
log = log.child({ revisionID: newRevision.id });
log = log.child({ revisionID: newRevision.id }, true);
if (actions.length > 0) {
// Insert and handle creating the actions.
@@ -34,11 +34,14 @@ const moderate = (
// TODO: wrap these operations in a transaction?
// Create the logger.
const log = logger.child({
...input,
tenantID: tenant.id,
newStatus: status,
});
const log = logger.child(
{
...input,
tenantID: tenant.id,
newStatus: status,
},
true
);
// Update the Comment's status.
const result = await updateCommentStatus(
@@ -22,9 +22,12 @@ export const spam: IntermediateModerationPhase = async ({
}): Promise<IntermediatePhaseResult | void> => {
const integration = tenant.integrations.akismet;
const log = logger.child({
tenantID: tenant.id,
});
const log = logger.child(
{
tenantID: tenant.id,
},
true
);
// We can only check for spam if this comment originated from a graphql
// request via an HTTP call.
@@ -32,7 +32,7 @@ export const toxic: IntermediateModerationPhase = async ({
return;
}
const log = logger.child({ tenantID: tenant.id });
const log = logger.child({ tenantID: tenant.id }, true);
const integration = tenant.integrations.perspective;
@@ -98,7 +98,7 @@ export default class NotificationContext {
this.now = now;
this.config = config;
this.signingConfig = signingConfig;
this.log = log.child({ tenantID: tenant.id });
this.log = log.child({ tenantID: tenant.id }, true);
}
/**
+1 -1
View File
@@ -2,7 +2,7 @@ import DataLoader from "dataloader";
import LRU from "lru-cache";
import { Db } from "mongodb";
import { loadPersistedQueries } from "coral-server/graph/tenant/persisted";
import { loadPersistedQueries } from "coral-server/graph/common/persisted";
import logger from "coral-server/logger";
import {
getQueries,
+14 -8
View File
@@ -101,10 +101,13 @@ export async function remove(
includeComments: boolean = false
) {
// Create a logger for this function.
const log = logger.child({
storyID,
includeComments,
});
const log = logger.child(
{
storyID,
includeComments,
},
true
);
log.debug("starting to remove story");
@@ -254,10 +257,13 @@ export async function merge(
sourceIDs: string[]
) {
// Create a logger for this operation.
const log = logger.child({
destinationID,
sourceIDs,
});
const log = logger.child(
{
destinationID,
sourceIDs,
},
true
);
if (sourceIDs.length === 0) {
log.warn("cannot merge from 0 stories");
@@ -31,7 +31,7 @@ class Scraper {
constructor(rules: Rule[]) {
this.rules = rules;
this.log = logger.child({ taskName: "scraper" });
this.log = logger.child({ taskName: "scraper" }, true);
}
public async scrape(
@@ -40,7 +40,7 @@ class Scraper {
): Promise<GQLStoryMetadata | null> {
// Grab the page HTML.
const log = this.log.child({ storyURL: url });
const log = this.log.child({ storyURL: url }, true);
const options: RequestInit = {
headers: {
+2 -2
View File
@@ -89,7 +89,7 @@ export async function install(
// TODO: (wyattjoh) perform any pending migrations.
logger.info({ tenant: input }, "installing tenant");
logger.info("installing tenant");
// Create the Tenant.
const tenant = await createTenant(mongo, i18n, input, now);
@@ -97,7 +97,7 @@ export async function install(
// Update the tenant cache.
await cache.update(redis, tenant);
logger.info({ tenant }, "a tenant has been installed");
logger.info({ tenantID: tenant.id }, "a tenant has been installed");
return tenant;
}
+9
View File
@@ -1,6 +1,7 @@
import { NextFunction, Request as ExpressRequest, Response } from "express";
import { Logger } from "coral-server/logger";
import { PersistedQuery } from "coral-server/models/queries";
import { Tenant } from "coral-server/models/tenant";
import { User } from "coral-server/models/user";
import TenantCache from "coral-server/services/tenant/cache";
@@ -12,6 +13,7 @@ export interface CoralRequest {
tenant: TenantCache;
};
tenant?: Tenant;
persisted?: PersistedQuery;
logger: Logger;
}
@@ -25,3 +27,10 @@ export type RequestHandler = (
res: Response,
next: NextFunction
) => void;
export type ErrorRequestHandler = (
err: Error,
req: Request,
res: Response,
next: NextFunction
) => void;