Winston Http Transport not working inside MochaJS custom Reporter - mocha.js

I'm trying to log errors using Http Transport and it's not working properly inside the custom report EVENT_TEST_FAIL. transport.Console is logging the error when a test fails but it is not passing the data to the log server.
This is my code inside the custom reporter
runner
.on(EVENT_TEST_FAIL, (test, err) => {
ddLogger.log('error', 'HELLO')
})
Here's the code for ddLogger:
const httpTransport = new transports.Http({
host: 'http-intake.logs.datadoghq.com',
path: `/v1/input/${process.env.DATADOG_API_KEY}?ddsource=nodejs&service=PEPINO`,
ssl: true,
})
const ddLogger = createLogger({
level: 'error',
exitOnError: false,
format: format.json(),
transports: [
httpTransport,
// new transports.Console
],
})
This outputs {"level":"error","message":"HELLO"} in Console but data is not passed to log server.

Well, as it so happens you have wrongly declared your transport, which should be
transports: [ new transports.Http(httpTransport), ... ]

Related

Graphql subscription in playground during local development throwing "Could not connect to websocket endpoint" in basic nestjs project

This is happening on a simple project during local development, so cloud infrastructure isn't an issue.
This is also happening in the application playground.
My module registration:
GraphQLModule.forRootAsync<ApolloDriverConfig>({
driver: ApolloDriver,
imports: [YeoConfigModule],
useFactory: (configService: YeoConfigService<AppConfig>) => {
const config: ApolloDriverConfig = {
debug: true,
subscriptions: {
'graphql-ws': true,
},
playground: true,
autoSchemaFile: './apps/event-service/schema.gql',
sortSchema: true,
context: ({ req, res }) => ({ req, res }),
};
const origins = configService.get('CORS_ORIGINS')();
config.cors = { origin: origins, credentials: true };
// config.path = '/apis/event-service/graphql';
return config;
},
inject: [YeoConfigService],
My app startup:
async function bootstrap(): Promise<void> {
const app = await getApp();
await app.listen(process.env.PORT ?? 3600);
}
bootstrap();
My versions:
"graphql-ws": "5.11.2",
"graphql-redis-subscriptions": "2.5.0"
"#apollo/gateway": "2.1.3",
"#nestjs/graphql": "10.1.3",
"graphql": "16.5.0",
Result:
{
"error": "Could not connect to websocket endpoint ws://localhost:3600/graphql. Please check if the endpoint url is correct."
}
Any ideas why this isn't working as expected? I've been reading the nestjs docs up at https://docs.nestjs.com/graphql/subscriptions but there's nothing that I can find about extra setup required other than adding
subscriptions: {
'graphql-ws': true,
},
when registering the graphql module.
For anyone else stumbling upon this, I have started using altair which allows me to specify the ws endpoint as well as the type of connection, among which there is a graphql-ws option.
So I went with it.
If anyone knows how to achieve this using the playground referred in the original answer, happy to mark that one as the right answer over my own.

Svelte Proxy with rollup?

I'm trying to proxy requests from a Svelte app to a different port, where my backend API runs. I want to use a rollup proxy in the dev environment.
I read the alternative of using a webpack proxy here, but I want to give rollup proxy a try.
This is not an issue in production.
As suggested, I tried configuring rollup-plugin-dev However, whenever I make a request to weatherforecast I still get an CORS error. Below is my configuration and the call:
import dev from 'rollup-plugin-dev'
// other code
export default {
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/build/bundle.js'
},
plugins: [
dev({
proxy: [{ from: '/weatherforecast', to: 'https://localhost:7262' }]
}),
// other code
];
and App.svelte looks like this:
<script>
import { onMount } from "svelte";
const endpoint = "/weatherforecast";
onMount(async function () {
try {
const response = await fetch(endpoint);
const data = await response.json();
console.log(data);
} catch (error) {
console.log(error);
}
});
</script>
Any help in solving this issue is appreciated.
What's happening is the proxy is passing through the CORS headers un-touched, so you're basically interacting with the API as though the proxy wasn't even there, with respect to CORS.
I'll note that you can get around this in dev, but keep in mind this problem will come up in production too, so you may just need to rethink how you're getting this data.
For development though, you can use something like cors-anywhere. This is a middleware that you can run through your dev server that can rewrite the headers for you.
To configure rollup-proxy on dev environment, you need to remove the call to the serve method, call the dev method and move the proxy calls inside the dev method:
import dev from 'rollup-plugin-dev'
// other code
export default {
input: 'src/main.js',
output: {
// other code
commonjs(),
// enable the rollup-plugin-dev proxy
// call `npm run start` to start the server
// still supports hot reloading
!production && dev({
dirs: ['public'],
spa: 'public/index.html',
port: 5000,
proxy: [
{ from: '/weatherforecast', to: 'https://localhost:7262/weatherforecast' },
],
}),
// line below is no longer required
// !production && serve(),
// other code
];

Passing a unique session ID to Winston logger

I am trying to figure out if there is a way to use a unique (per request) session ID in all of the winston logger calls when an HTTP request is made.
Elaboration on the issue:
Given a scenario that several hundred requests hit a website per minute and each request passes through different functions which log out various messages.
My goal is to log messages including a unique session ID per request using winston logger, until the response is sent.
I generate a unique session ID for the request using app.use(session(...)) from express-session library.
Using morgan, the HTTP logs are printed with a unique session ID like so:
logger = winston.createLogger(...);
const myStream = {
write: (text: string) => {
logger.info(text);
}
}
morgan.token('sessionid', function (req, res) { return req['sessionID'] });
app.use(morgan(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent" ["SESSION_ID :sessionid"]', { stream: myStream }));
However, I also want to use the same session ID in other logger.* functions elsewhere in the code. I am able to do that but as the number of simulataneous requests (using k6 load test) increases, the session ID gets overwritten by a new session ID of another request.
My code for using the session ID in request in a winston transport is:
public static initializeLogger(appInstance: express.Application) {
if (!appInstance) throw new Error(`Cannot initialize logger. Invalid express.Application instance passed. Logging may not be available`);
appInstance.use((req, res, next) => {
//this.m_sessionID = req["sessionID"];
this.m_logger.clear();
this.m_logger = winston.createLogger({
level: LOG_LEVEL,
levels: winston.config.syslog.levels,
format: winston.format.json(),
transports: [
new winston.transports.Console({ format: winston.format.simple() }),
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'debug.log', level: 'debug' }),
new WinstonCloudWatch({
logGroupName: CLOUDWATCH_LOG_GROUP_NAME,
logStreamName: function () {
let date = new Date().toISOString().split('T')[0];
return 'k-server-logs-' + date;
},
awsRegion: AWS_REGION,
awsAccessKeyId: process.env.AWS_ACCESS_KEY_ID,
awsSecretKey: process.env.AWS_SECRET_ACCESS_KEY,
retentionInDays: process.env.CLOUDWATCH_LOG_RETENTION_DAYS ? Number(process.env.CLOUDWATCH_LOG_RETENTION_DAYS) : 30,
messageFormatter: (log) => {
return `${JSON.stringify({
message: log.message,
sessionID: req["sessionID"],
level: log.level
})}`
}
})
],
});
next();
});
}
I was hoping putting the winston logger in app.use(...) middleware would set up the cloudwatch transport for the winston logger along with using the req.sessionID as each request comes in.
However, this setup isn't working. If I send even 10 simultaneous requests, this code breaks and the sessionID is incorrectly stamped on logger.* messages and/or duplicated across multiple messages.
I reviewed other implementations such as https://solidgeargroup.com/en/express-logging-global-unique-request-identificator-nodejs/ but could not get it to work.
Hoping for some advice - I am sure my setup is off.
Thank you in advance.
Key hint from https://solidgeargroup.com/en/express-logging-global-unique-request-identificator-nodejs/
Use express-http-context which has a set and get function that will ensure that the unique session ID is available throughout your code.
import httpContext from 'express-http-context';
...
...
logger.add(new WinstonCloudWatch({
level:LOG_LEVEL,
logGroupName: CLOUDWATCH_LOG_GROUP_NAME,
logStreamName: function () {
let date = new Date().toISOString().split('T')[0];
return `${process.env.CLOUDWATCH_LOG_FILE_NAMEPREFIX}-logs-${date}`;
},
awsRegion: AWS_REGION,
awsAccessKeyId: process.env.AWS_ACCESS_KEY_ID,
awsSecretKey: process.env.AWS_SECRET_ACCESS_KEY,
retentionInDays: process.env.CLOUDWATCH_LOG_RETENTION_DAYS ? Number(process.env.CLOUDWATCH_LOG_RETENTION_DAYS) : 30,
messageFormatter: (log) => {
return `${JSON.stringify({
message: log.message,
**sessionID: httpContext.get('reqId')**,
level: log.level
})}`
}
}));

Why is my koa application timing out when testing a route with Jest/Supertest

Summary of Problem
Receiving : Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.Timeout when trying to run a test with Jest and supertest.
Specs
Koa2 project, Jest/Supertest testing, Babel 7.9.0 recommended configuration
What I've tried
I have a simple test from the same file running which I omitted from the code below for brevity. I've also tried sending an HTTP request from the browser - this file is imported & 'listen'ed in a server file. The request is failing because it is blocked by a CORS policy - I think this is a problem for another day and isn't affecting my test timing out.
I also tried removed .callback() from the supertest(..) call:
const response = await supertest(app).post('/save-material');
at which point I get TypeError: app.dress is not a function.
Here is the content of my test file:
process.env.NODE_ENV = 'test';
const app = require('../../src/server/app.js')
const supertest = require('supertest')
test('save-material returns response', async() => {
const response = await supertest(app.callback()).post('/save-material');
expect(response.status).toBe(200);
expect(response.body.status).toBe('success');
expect(response.body.msg).toBe('Material saved')
});
Here is the content of the imported file (app.js) from above:
require('#babel/register'); // not entry point - but is entry point for some tests
const Koa = require('koa');
var Router = require('koa-router')
const app = new Koa();
const router = new Router();
router
.post('/save-material', async(ctx) => {
ctx.response = {
status: 'success',
msg: 'Material saved'
}
return ctx;
})
app.use(router.routes());
app.use(router.allowedMethods());
module.exports = app;

graphql playground behaving weirdly running on heroku

So i have an apollo-server running using apollo-server-express:
const PORT = process.env.PORT || 8000
const graphqlPath = process.env.GRAPHQL || 'graphql'
const app = express()
app.use(cors())
app.use(bodyParser.text({ type: 'application/graphql' }))
const gqlServer = new ApolloServer({
typeDefs: schema,
resolvers,
context: {
me: users[1]
},
debug: true,
tracing: true
})
gqlServer.applyMiddleware({ app, path: `/${graphqlPath}` })
app.listen(PORT, () => console.log(`graphql listening on port ${PORT}`))
module.exports = app
it runs perfectly on localhost, but deploying it to heroku, it becomes weird when i run the playground:
it says Server cannot be reached
I can't get the schema
the queries run (sometimes) and immediately after i see the result, it changes to that json error object
when i copy the curl request, and run it on my terminal, i always get the result without any problems
Here's a sample of the console errors:
POST <graphql_server_url> 400 (Bad Request)
Error: Response not successful: Received status code 400
Try adding introspection and playground to your ApolloServer config and set to true. They get turned off automatically when the Node environment is set to production, but this way you can enable it in prod. Reference: https://www.apollographql.com/docs/apollo-server/v2/testing/graphql-playground/#enabling-graphql-playground-in-production
const gqlServer = new ApolloServer({
typeDefs: schema,
resolvers,
context: {
me: users[1]
},
debug: true,
tracing: true,
introspection: true,
playground: true
})
adding introspection: true to new ApollowServer object will solve the porblem

Resources