multiple logger levels for multiple files in sails.js - sails.js

I want to create separate files for every log levels, and it should store respective files. says,
sails.log.info('Info log');
It should store at info.log file.
var logger = new (winston.Logger)({
transports: [
new (winston.transports.Console)({}),
new (winston.transports.File)({
name: 'info-file',
filename: 'info.log',
level: 'info',
json: false
}),
new (winston.transports.File)({
name: 'error-file',
filename: 'error.log',
level: 'error',
json: false
}),
new (winston.transports.File)({
name: 'debug-file',
filename: 'debug.log',
level: 'debug',
json: false
})
]
});
In config/log.js
custom: logger
My problem is some logs are not shows in terminal, and info.log and debug.log files has not only info and debug log respectively.
How to achieve this?

Well, looks like Winston writes to logs based on their numeric levels. So that error messages will be always written to info log, but info never to error log.
So I think it is better to separate to different instances in config/bootstrap.js:
sails.warnLog = new (winston.Logger)({
transports: [
new (winston.transports.Sentry)({
name: 'warn-Sentry',
dsn: '{my account dsn}',
patchGlobal: true
level: 'warn'
})
]});
sails.infLog = new (winston.Logger)({
transports: [
new (winston.transports.Loggly)({
name: 'info-Loggly',
subdomain: '{my subdomain}',
inputToken: '{my input token}'
level: 'info'
})
]});
sails.verbLog = new (winston.Logger)({
transports: [
new (winston.transports.Console)({
name: 'verb-console',
timestamp: true,
prettyPrint: true,
colorize: true,
level: 'verbose'
})
]});
And then you can write to log:
sails.warnLog.warn('Warning');
sails.infLog.info('Information');
sails.verbLog.verbose('Verbose');

Related

assumed-role is not authorized to perform: route53:ListHostZonesByDomain; Adding a Route53 Policy to a CodePipeline CodeBuildAction's Assumed Rule

My goal is to create a website at subdomain.mydomain.com pointing to a CloudFront CDN distributing a Lambda running Express that's rendering an S3 website. I'm using AWS CDK to do this.
I have an error that says
[Error at /plants-domain] User: arn:aws:sts::413025517373:assumed-role/plants-pipeline-BuildCDKRole0DCEDB8F-1BHVX6Z6H5X0H/AWSCodeBuild-39a582bf-8b89-447e-a6b4-b7f7f13c9db1 is not authorized to perform: route53:ListHostedZonesByName
It means:
[Error at /plants-domain] - error in the stack called plants-domain
User: arn:aws:sts::1234567890:assumed-role/plants-pipeline-BuildCDKRole0DCEDB8F-1BHVX6Z6H5X0H/AWSCodeBuild-39a582bf-8b89-447e-a6b4-b7f7f13c9db is the ARN of the Assumed Role associated with my object in the plants-pipeline executing route53.HostedZone.fromLookup() (but which object is it??)
is not authorized to perform: route53:ListHostedZonesByName the Assumed Role needs additional Route53 permissions
I believe this policy will permit the object in question to lookup the Hosted Zone:
const listHostZonesByNamePolicy = new IAM.PolicyStatement({
actions: ['route53:ListHostedZonesByName'],
resources: ['*'],
effect: IAM.Effect.ALLOW,
});
The code using Route53.HostedZone.fromLookup() is in the first stack domain.ts. My other stack consumes the domain.ts template using CodePipelineAction.CloudFormationCreateUpdateStackAction (see below)
domain.ts
// The addition of this zone lookup broke CDK
const zone = route53.HostedZone.fromLookup(this, 'baseZone', {
domainName: 'domain.com',
});
// Distribution I'd like to point my subdomain.domain.com to
const distribution = new CloudFront.CloudFrontWebDistribution(this, 'website-cdn', {
// more stuff goes here
});
// Create the subdomain aRecord pointing to my distribution
const aRecord = new route53.ARecord(this, 'aliasRecord', {
zone: zone,
recordName: 'subdomain',
target: route53.RecordTarget.fromAlias(new targets.CloudFrontTarget(distribution)),
});
pipeline.ts
const pipeline = new CodePipeline.Pipeline(this, 'Pipeline', {
pipelineName: props.name,
restartExecutionOnUpdate: false,
});
// My solution to the missing AssumedRole synth error: Create a Role, add the missing Policy to it (and the Pipeline, just in case)
const buildRole = new IAM.Role(this, 'BuildRole', {
assumedBy: new IAM.ServicePrincipal('codebuild.amazonaws.com'),
path: '/',
});
const listHostZonesByNamePolicy = new IAM.PolicyStatement({
actions: ['route53:ListHostedZonesByName'],
resources: ['*'],
effect: IAM.Effect.ALLOW,
});
buildRole.addToPrincipalPolicy(listHostZonesByNamePolicy);
pipeline.addStage({
// This is the action that fails, when it calls `cdk synth`
stageName: 'Build',
actions: [
new CodePipelineAction.CodeBuildAction({
actionName: 'CDK',
project: new CodeBuild.PipelineProject(this, 'BuildCDK', {
projectName: 'CDK',
buildSpec: CodeBuild.BuildSpec.fromSourceFilename('./aws/buildspecs/cdk.yml'),
role: buildRole, // this didn't work
}),
input: outputSources,
outputs: [outputCDK],
runOrder: 10,
role: buildRole, // this didn't work
}),
new CodePipelineAction.CodeBuildAction({
actionName: 'Assets',
// other stuff
}),
new CodePipelineAction.CodeBuildAction({
actionName: 'Render',
// other stuff
}),
]
})
pipeline.addStage({
stageName: 'Deploy',
actions: [
// This is the action calling the compiled domain stack template
new CodePipelineAction.CloudFormationCreateUpdateStackAction({
actionName: 'Domain',
templatePath: outputCDK.atPath(`${props.name}-domain.template.json`),
stackName: `${props.name}-domain`,
adminPermissions: true,
runOrder: 50,
role: buildRole, // this didn't work
}),
// other actions
]
});
With the above configuration, unfortunately, I still receive the same error:
[Error at /plants-domain] User: arn:aws:sts::413025517373:assumed-role/plants-pipeline-BuildCDKRole0DCEDB8F-1BHVX6Z6H5X0H/AWSCodeBuild-957b18fb-909d-4e22-94f0-9aa6281ddb2d is not authorized to perform: route53:ListHostedZonesByName
With the Assumed Role ARN, is it possible to track down the object missing permissions? Is there another way to solve my IAM/AssumedUser role problem?
Here is the answer from the official doco: https://docs.aws.amazon.com/cdk/api/latest/docs/pipelines-readme.html#context-lookups
TLDR:
pipeline by default cannot do lookups -> 2 options:
synth on dev machine (make sure a dev has permissions)
add policy for lookups
new CodePipeline(this, 'Pipeline', {
synth: new CodeBuildStep('Synth', {
input: // ...input...
commands: [
// Commands to load cdk.context.json from somewhere here
'...',
'npm ci',
'npm run build',
'npx cdk synth',
// Commands to store cdk.context.json back here
'...',
],
rolePolicyStatements: [
new iam.PolicyStatement({
actions: ['sts:AssumeRole'],
resources: ['*'],
conditions: {
StringEquals: {
'iam:ResourceTag/aws-cdk:bootstrap-role': 'lookup',
},
},
}),
],
}),
});
Based on the error, the pipeline role (and it would work at the stage or action...)
By default a new role is being created for the pipeline:
role?
Type: IRole (optional, default: a new IAM role will be created.)
The IAM role to be assumed by this Pipeline.
Instead, when you are constructing your pipeline add the buildRole there:
const pipeline = new CodePipeline.Pipeline(this, 'Pipeline', {
pipelineName: props.name,
restartExecutionOnUpdate: false,
role: buildRole
});
Based on your pipeline you never assigned the role to the relevant stage action according to the docs:
pipeline.addStage({
stageName: 'Deploy',
actions: [
// This is the action calling the compiled domain stack template
new CodePipelineAction.CloudFormationCreateUpdateStackAction({
...
role: buildRole, // this didn't work
}),
// other actions
]
});
Should be:
pipeline.addStage({
stageName: 'Deploy',
actions: [
// This is the action calling the compiled domain stack template
new CodePipelineAction.CloudFormationCreateUpdateStackAction({
....
deploymentRole: buildRole
}),
]
});
Why is it deploymentRole instead of just role, no one knows.

"Invalid Cucumber JSON file found" while generating report with cucumber-html-reporter

While using cucumber-html-reporter to generate a report in case of sharding with muliple chrome instances, I am getting "Error: Invalid Cucumber JSON file found"
Below is my configuration,
var reporter = require('cucumber-html-reporter');
var options = {
theme: 'bootstrap',
reportSuiteAsScenarios: true,
brandTitle: 'E2E Report',
name: _env.toUpperCase(),
metadata: {
"Test Environment": _env,
"Browser": 'Chrome',
"Platform": process.platform,
"Parallel": "Scenarios",
"Executed": "Remote"
}
};
Error:
[16:57:23] E/launcher - Error: Error: Invalid Cucumber JSON file found under ./e2e-reports/rest-api: e2e-reports/rest-api/results.25181.json
This happens when I try to use tag filters while running the suite. Due to which one of the feature file shows 0 scenarios have run. And as I have enabled sharding the result json specific to that chrome process shows empty. Is there any way to handle this?
You can set ignoreBadJsonFile as true in your cucumber-html-reporter options. This will ignore the bad json files and generates the report.
In your case, add as below:
var reporter = require('cucumber-html-reporter');
var options = {
theme: 'bootstrap',
reportSuiteAsScenarios: true,
ignoreBadJsonFile: true,
brandTitle: 'E2E Report',
name: _env.toUpperCase(),
metadata: {
"Test Environment": _env,
"Browser": 'Chrome',
"Platform": process.platform,
"Parallel": "Scenarios",
"Executed": "Remote"
}
};

Karma gives 404 for images (AureliaJS)

Using the Aurelia CLI I run my unit tests with au test. Karma logs to console (over and over again for multiple requests):
WARN [web-server]: 404: /src/assets/images/avatar-backup.png
I understand that including my image files with tests isn't necessary and I could change the log levels to ignore these warnings, but this seems like it should really be a non issue. If for nothing else I want to know why and how to fix this for my own curiosity.
I've tried a combination of different methods found here and here (and elsewhere), but I still cannot figure out what I'm doing wrong. I'm still somewhat new to Karma and Aurelia so maybe I'm missing some fundamental understanding... I don't know.
Currently my this is my karma.conf.js
'use strict';
const path = require('path');
const project = require('./aurelia_project/aurelia.json');
const tsconfig = require('./tsconfig.json');
let testSrc = [
{ pattern: project.unitTestRunner.source, included: false },
'test/aurelia-karma.js'
];
let output = project.platform.output;
let appSrc = project.build.bundles.map(x => path.join(output, x.name));
let entryIndex = appSrc.indexOf(path.join(output, project.build.loader.configTarget));
let entryBundle = appSrc.splice(entryIndex, 1)[0];
// Added the image file sources
let imgFiles = [
{pattern: 'src/assets/images/*', watched: false, included: false, served: true, nocache: false},
// Added an exact path in case my pattern was somehow wrong, still doesn't load
{pattern: 'src/assets/images/avatar-backup.png', watched: false, included: false, served: true, nocache: false}
];
// Concat imgFiles to file array
let files = [entryBundle].concat(imgFiles).concat(testSrc).concat(appSrc);
module.exports = function(config) {
config.set({
basePath: '',
frameworks: [project.testFramework.id],
files: files,
exclude: [],
preprocessors: {
[project.unitTestRunner.source]: [project.transpiler.id]
},
typescriptPreprocessor: {
typescript: require('typescript'),
options: tsconfig.compilerOptions
},
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
// client.args must be a array of string.
// Leave 'aurelia-root', projectName.paths.root in this order so we can find
// the root of the aurelia projectName.
client: {
args: ['aurelia-root', project.paths.root]
},
browserConsoleLogOptions: {
terminal: true,
level: ""
},
// Not sure how to use proxy in combination with my added file sources or if I even need to...
// proxies: {
// "/img/": "http://localhost:9876/base/src/assets/images/"
// },
});
};
My app file structure looks like:
app
- src
- assets
- images
- (..images)
- test
- unit
- (..tests)

sails lifecycle - custom service and config.log

I defined a l.js under /api/services
exports.i = sails.log.info;
exports.v = sails.log.verbose;
exports.err = sails.log.error;
exports.w = sails.log.warn;
exports.d = sails.log.debug;
It works fine but when I want to define custom logger in /config/log.js
let customLogger = new (winston.Logger)({
transports: [
new (winston.transports.Console, winston.transports.File)({
name: 'file.info',
level: 'info',
filename: logPath + '/server-info.log',
json: true
}),
new (winston.transports.Console, winston.transports.File)({
name: 'file.warning',
level: 'warning',
filename: logPath + '/server-warning.log',
json: true
}),
new (winston.transports.File)({
name: 'file.error',
level: 'error',
filename: logPath + '/server-error.log',
json: true
})
]
});
module.exports.log = {
level: 'info',
custom: customLogger,
};
When I use sails.log.error("123"); l.err("456") in controller, only "123" showed in server-error.log file. "456" only print to console.
When I check sails doc about lifecycle, it seems /config/log.js loaded before /api/services. How should I modify my code?
Thanks
Although config/log.js is loaded before api/services/l.js, (my feeling is) assignment of custom logger defined in log.js to sails.log.<level> happens after the service is loaded.
Hence the behavior.
Re-assigning on lifted event fixes this. Use this code in l.js:
exports.err = sails.log.error;
sails.on('lifted', function() {
console.log('lifted event');
// Re-assign here
exports.err = sails.log.error;
});
Do similarly for other methods of the service.

Using Winston and Morgan to log in Sails

In the config/log.js file for Sails this is my code:
var express = require("express");
var app = express();
var winston = require('winston');
var logger = new(winston.Logger)({
transports: [
new(winston.transports.File)({
level: 'info',
timestamp: true,
filename: './logFile.log',
handleExceptions: true,
json: true,
colorize: false
}),
new(winston.transports.Console)({
level: 'debug',
timestamp: true,
handleExceptions: true,
json: false,
colorize: true
})
],
exitOnError: false
});
logger.stream = {
write: function (message, encoding) {
logger.verbose(message);
}
};
app.use(require('morgan')("combined", {"stream": logger.stream}));
module.exports.log = {
level: 'info',
custom: logger
};
I'm trying to use morgan along with winston to log all the HTTP requests. I found an example online that said to do it this way, and this makes sense to me, but for some reason my log file isn't showing any of the requests that are made. The winston part is fine as it is logging all the information that it should be, but I don't know how to get morgan to work with winston. Any advice or suggestions? Thanks!
Morgan is an express middleware so it should be loaded as a custom middleware to Sails.
To do that add the following to config/http.js:
customMiddleware: function(app) {
app.use(require('morgan')("combined", {"stream": sails.config.log.custom.stream}));
}