I'm currently running a node application with Pm2, but am struggling to get logs.
Currently, if I start the script with just node index.js my logger function (using winston) sends the logs to the screen just fine. The first two lines in the below video ("IS THIS SHOWING UP" and "YA") are from console.log statements inside my javascript files, and the latter lines are from my logger function. It looks like this:
However, in the deployment of my server, I'm using an ecosystem.config.js file with Pm2. When I run my server with pm2 start index.js, the logger also works. HOWEVER, when I start my server using my ecosystem file, the pm2 instance only sends the console.log statements to the output, not the logs output by the winston logger.
This means that I've got something misconfigured in my ecosystem.config.js file. What's going wrong?
package.json (script that kicks off the pm2 instance)
{
"name": "graphqlCourse",
...
"scripts": {
"prod:serve": "NODE_ENV=production pm2 startOrRestart ecosystem.config.js"
},
"dependencies": {
...
ecosystem.config.js
module.exports = {
apps: [
/// I believe that something is misconfigured in here relating to logging.....
{
name: process.env.APP_NAME,
args: ["--color"],
interpreter: process.env.NODE_PATH,
cwd: path.resolve(process.env.PROJECT_PATH, 'current' ),
script: 'dist/index.js',
instances: process.env.INSTANCES || 0,
exec_mode: "cluster",
env: {
...process.env,
},
},
],
deploy: {
production: {
user: "harrison",
host: process.env.HOST,
key: "~/.ssh/id_rsa2",
ref: "origin/master",
repo: process.env.GIT_REPO,
path: process.env.PROJECT_PATH,
"pre-deploy-local": `scp -Cr envs harrison#${process.env.HOST}:${process.env.PROJECT_PATH}/current`,
"post-deploy": `yarn install --ignore-engines && \
pwd && \
yarn prod:build && \
yarn prod:serve`,
},
},
};
-- EDIT --
Here's my logger as well:
import winston, { format } from "winston";
import "winston-daily-rotate-file"; // Attaches new transport to winston.transports
// Define the custom settings for each transport (file, console)
let consoleOptions = {
level: "info",
handleExceptions: true,
stderrLevels: ["error"],
silent: process.env.SILENT === "true",
format: format.combine(
format.colorize(),
format.align(),
format.printf((info) => {
const { level, message } = info;
return `[${level}]: ${message}`;
})
),
};
let consoleTransport = new winston.transports.Console(consoleOptions);
// Log rotation
const transport = new winston.transports.DailyRotateFile({
filename: `API_${process.env.NODE_ENV}.log`,
dirname: `./${
process.env.NODE_ENV === "production" ? "dist" : "server"
}/logs`,
frequency: null, // Rely on date pattern, rotate daily
datePattern: "YYYY-MM-DD",
zippedArchive: true,
maxSize: "10m",
maxFiles: "14d",
format: format.combine(format.timestamp(), format.json()),
});
transport.on("rotate", (oldFileName, newFilename) => {
console.log(`ROTATING LOGS. OLD: ${oldFileName} -- NEW: ${newFilename}`);
});
// Handles input from Morgan.
var writer = new winston.createLogger({
transports: [transport],
});
// Handles logger.XX calls from within app.
export const logger = new winston.createLogger({
transports: [consoleTransport, transport],
exitOnError: false, // do not exit on handled exceptions
});
// Recieves message from morganToWinston
logger.stream = {
write: function (message) {
writer.info(message);
},
};
Related
I try to configure hot reload on my Nestjs application using this article: https://docs.nestjs.com/recipes/hot-reload
I followed exactly the instructions in the first section ("With CLI") but it fails for me. But I do know the reason, just don't know how to resolve this issue. My hot reload script in package.json is exactly as the article says, except 1 change:
"start:dev": "dotenv -e ./envs/.env.development -e ../../prisma/.env.development nest build --watch",
This is my script. As you can see, I apply the process with some environment variables. When running in this way, application boots fine, but Hot Reload won't work. When booting only with "start:dev": "nest build --watch",
It runs with Hot Reload. (Note that I configure webpack in nest-cli.json file, this is why it missing in script statement).
Anyone could tell why applying my own envs makes this issue?
webpack.config.js file:
const nodeExternals = require('webpack-node-externals');
const { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');
const configuration = (options, webpack) => ({
...options,
entry: ['webpack/hot/poll?100', options.entry],
externals: [
nodeExternals({
allowlist: ['webpack/hot/poll?100'],
}),
],
plugins: [
...options.plugins,
new webpack.HotModuleReplacementPlugin(),
new webpack.WatchIgnorePlugin({
paths: [/\.js$/, /\.d\.ts$/],
}),
new RunScriptWebpackPlugin({ name: options.output.filename, autoRestart: false }),
],
});
module.exports = configuration;
nest-cli.json file:
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "#nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"webpack": true,
"webpackConfigPath": "./webpack.config.js",
"deleteOutDir": true
}
}
main.ts file:
declare const module: any;
async function bootstrap() {
const prisma = new PrismaClient();
// * https://github.com/prisma/prisma/issues/5430#issuecomment-1098715558
await prisma.$runCommandRaw({
createIndexes: 'RefreshToken',
indexes: [
{
key: {
createdAt: 1,
},
name: 'Refresh Token Index',
expireAfterSeconds: JWT_REFRESH_TOKEN_DURATION_MINUTES * 60,
},
],
});
const app = await NestFactory.create(AppModule);
if (module.hot) {
module.hot.accept();
module.hot.dispose(() => app.close());
}
const port = config.get('port', { infer: true });
await app.listen(port);
}
bootstrap();
Ny env file:
NODE_ENV="development"
PORT="3000"
I'm new with Appium and WebdriverIO, I have an app created (a .zip file) and I want to test it with those 2 frameworks.
TL:DR - just go to the fourth code block.
I followed some tutorials and created a project containing
config files
test files
and of course a package.json.
First things first, my package.json:
{
"name": "my-test",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"wdio": "wdio run ./config/wdio.conf.js",
"ios.app": "./node_modules/.bin/wdio ./config/wdio.ios.app.conf.js"
},
"devDependencies": {
"#wdio/appium-service": "^7.16.16",
"#wdio/cli": "^7.16.16",
"#wdio/devtools-service": "^7.16.16",
"#wdio/local-runner": "^7.16.16",
"#wdio/mocha-framework": "^7.16.15",
"#wdio/spec-reporter": "^7.16.14",
"chai": "^4.3.6",
"chromedriver": "^99.0.0",
"wdio-chromedriver-service": "^7.2.8",
"webdriverio": "^7.16.16"
}
}
Then, my config files, divided in shared and ios :
shared.conf.js
exports.config = {
// ====================
// Runner and framework
// Configuration
// ====================
runner: "local",
framework: "mocha",
mochaOpts: {
timeout: 30000,
},
sync: true,
logLevel: "info",
deprecationWarnings: true,
bail: 0,
baseUrl: "localhost",
// path for appium sessions
path: "/wd/hub",
waitforTimeout: 15000,
connectionRetryTimeout: 90000,
connectionRetryCount: 3,
reporters: ["spec"],
autoGrantPermissions: true,
autoAcceptAlerts: true,
nativeWebTap: true,
// ====================
// Appium Configuration
// ====================
services: [
[
"appium",
{
// For options see
// https://github.com/webdriverio/webdriverio/tree/master/packages/wdio-appium-service
args: {
// Auto download ChromeDriver
relaxedSecurity: true,
// chromedriverAutodownload: true,
// For more arguments see
// https://github.com/webdriverio/webdriverio/tree/master/packages/wdio-appium-service
},
command: "appium",
},
],
],
port: 4723,
};
wdio.ios.app.conf.js
const { join } = require("path");
const { config } = require("./shared.conf");
// ============
// Specs
// ============
config.specs = ["./tests/specs/**/*.spec.js"];
// ============
// Capabilities
// ============
// For all capabilities please check
// http://appium.io/docs/en/writing-running-appium/caps/#general-capabilities
config.capabilities = [
{
// The defaults you need to have in your config
platformName: "iOS",
maxInstances: 1,
// For W3C the appium capabilities need to have an extension prefix
// This is `appium:` for all Appium Capabilities which can be found here
// http://appium.io/docs/en/writing-running-appium/caps/
"appium:deviceName": "iPhone 7",
"appium:platformVersion": "15.2",
"appium:orientation": "PORTRAIT",
// `automationName` will be mandatory, see
// https://github.com/appium/appium/releases/tag/v1.13.0
"appium:automationName": "XCUITest",
// The path to the app
"appium:app": join(process.cwd(), "../../../my-test.zip"),
// Read the reset strategies very well, they differ per platform, see
// http://appium.io/docs/en/writing-running-appium/other/reset-strategies/
"appium:noReset": true,
// How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session
// default: 240
"appium:newCommandTimeout": 240,
},
];
exports.config = config;
So I created a very simple test file: there's a login screen, it finds the login textarea, writes the login, same for password, and push the button "signin":
describe("a test group", function () {
it("a test", async function () {
console.log("*******start*******");
// commands here
const selectUsername = 'type == "XCUIElementTypeTextField"';
const selectPassword = 'type == "XCUIElementTypeSecureTextField"';
const username = await $(`-ios predicate string:${selectUsername}`);
const password = await $(`-ios predicate string:${selectPassword}`);
const btnText = 'label == "SIGNIN"';
const loginBtn = await $(`-ios predicate string:${btnText}`);
await username.click();
await username.addValue("my#email.com");
await password.click();
await password.addValue("mypassword");
await loginBtn.click();
});
});
My issue here is that when the test is running
a) if I open the appium inspector, I can't find any running session, even if it has to exist somewhere:
plus (minor) I think the session never stops. If I re-run the test, the app running in the simulator shows the page of already logged-in, failing the test (because does not find the login/password fields).
Where are the sessions? and what I'm doing wrong?
Solved.
I was not able to edit the path in config file, but if I change the remote path in appium inspector to / , it finds the current session.
I need a basic logging system for a NodeJS application, so I'm doing some tests with log4js, which seems to be the standard for these cases. I need to print the messages both to the console and a file, so I wrote this code:
// Logger
var log4js = require('log4js');
log4js.configure({
appenders: {
'console': { type: 'console' },
'file': { type: 'file', filename: 'logs/mailer.log' }
},
categories: {
default: { appenders: ['file', 'console'], level: 'DEBUG' },
}
});
var logger = log4js.getLogger("Mailer");
logger.info("Starting application");
try {
// CODE TO READ APP CONFIG FILE
}
catch(e) {
logger.error("Couldn't read app configuration file (config.yml)");
// This is the trouble maker. It kills the app without flushing the logs
process.exit(1);
}
When I run the application, the logs appear like this:
[2019-07-29T16:07:24.763] [INFO] Mailer - Starting application
The problem is that I can see the messages in the console, but the log file remains empty. If I delete it and run the application again, it's created, so I suppose that the problem is a missing option or something like that.
Any suggestion?
To avoid changing the application logic and all the process.exit() calls, I've replaced the file appender by its synchronous version fileSync and now everything works as expected. So, the only thing I changed is the line where I declare the 'file' appender:
'file': { type: 'fileSync', filename: 'logs/mailer.log' }
Cheers!
You could use loggerWinston...I used it in my nodejs application and it works fine.
You should add it in your server.js (the file you use to start node)
const winston = require('winston');
const tsFormat = () => (new Date()).toLocaleTimeString();
global.loggerWinston = new (winston.Logger)({
transports: [
// colorize the output to the console
new (winston.transports.Console)({
timestamp: tsFormat,
colorize: true,
level: 'debug'
}),
new (winston.transports.File)({
filename: 'results.log',
timestamp: tsFormat,
// level: (process.env.NODE_ENV || 'development') === 'development' ? 'debug' : 'info'
level: 'info'
})
]
});
The results.log file should be added in your project folder.
This is the reference https://www.npmjs.com/package/winston
I'm getting the following error when trying to build:
Building for production...Error: ENOENT: no such file or directory, stat '/Users/me/Code/project/index.html'
Package: "prerender-spa-plugin": "^3.1.0"
File: vue.config.js:
const PrerenderSPAPlugin = require('prerender-spa-plugin');
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer;
const path = require('path');
module.exports = {
configureWebpack: config => {
if (process.env.NODE_ENV !== 'production') return;
return {
plugins: [
new PrerenderSPAPlugin({
staticDir: path.join(__dirname),
routes: ['/'],
minify: {
collapseBooleanAttributes: true,
collapseWhitespace: true,
decodeEntities: true,
keepClosingSlash: true,
sortAttributes: true,
},
renderer: new Renderer({
renderAfterDocumentEvent: 'render-event',
}),
}),
],
};
},
};
I don't have any routes, only a single index.html page.
Also, when I run yarn build and get that error, I try to kill the process in terminal but it keeps returning Building for production... without anything happening, and I have to quit terminal for it to stop.
Edit: I've also tried adding staticDir: path.join(__dirname, './public') but the build hangs without any errors.
Try adding headless: false to your renderer options. This will open a Chromium browser with your specified array of routes. Open the inspector in the Chromium browser and its very likely that you will see errors in the console.
i am trying to use grunt-ssh to automate deployment of server from my macbook pro.
So what i am trying to do with this task is to pull from my private bitbucket depository.
Deployment is looks okay once i do grunt deploy on bash but nothing gets pulled in server
This is my gruntfile:
module.exports = function(grunt) {
grunt.initConfig({
sshconfig: {
notify: {
host: 'mydomain.com',
port: 22,
username: 'root',
agent: process.env.SSH_AUTH_SOCK
}
},
sshexec: {
deploy: {
command: [
'cd notify',
'git pull origin master',
'npm install',
].join(' && '),
options: {
config: 'notify'
}
}
}
});
// Load the plugin that provides "sshevexc" task
grunt.loadNpmTasks('grunt-ssh');
// Register new task, deploy
grunt.registerTask('deploy', ['sshexec:deploy'], function(err){
if(err)
return false;
grunt.log.write('Done deploying!').ok();
});
}
Try adding in your sshconfig:
agentForward: true