Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removal of Winston #190

Merged
merged 11 commits into from
Nov 4, 2019
Merged

Removal of Winston #190

merged 11 commits into from
Nov 4, 2019

Conversation

briancullen
Copy link

Issue #, if available:
#10 #48 #103

Description of changes:
Alternative approach to upgrading the logging to that proposed in #188 - both requests aren't needed, it's one or the other.

Instead of upgrading the Winston library this change creates a simple logger that can be used instead. This change also standardises the logging format for in all environments and ensures that the specified logging level is honoured in lambda environments.

As far as I can tell the meta (or second argument to the logging functions) is only used in two places, both of which log out err.stack. As previously implemented this was converted into a JSON string which made it hard to read. The logger was changed so that strings (such as the stack trace) are printed out without being stringified.

Additionally the ability to change the log level was added whereas previously this could only be done via environmental variables before the module is loaded.

Some additional error checking may be required before merging this request and I'm making this initial submission to show the alternative mentioned in #188 is feasible.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Brian Cullen added 2 commits September 17, 2019 10:43
Test was written on the assumption that all paths conformed to the
unix format and line separators. This caused it to fail on Windows.
This change normalises the path to Unix format so that the tests
will work in both environments.
@briancullen briancullen changed the title Remove of Winston Removal of Winston Sep 22, 2019
Brian Cullen added 4 commits September 22, 2019 19:51
Old versions of node don't have console.debug. This change defaults
to console.log if a level method doesn't exist and then to a noop
function if console.log doesn't exist.
@willarmiros
Copy link
Contributor

willarmiros commented Sep 24, 2019

Hi @briancullen,
Thank you for yet another contribution. I would like to request that you make this PR against the 2.x branch instead of master. See #192 for more details. We have been discussing removing winston for some time since it is overkill for our relatively simple use case, so I think we'd go with this PR instead of #188, so this action isn't necessary on your other PR.

Sorry for this inconvenience, you can close this PR and we'll follow up on the new one once it's created.

@briancullen briancullen mentioned this pull request Sep 24, 2019
@briancullen
Copy link
Author

As requested by @willarmiros this pull request is being closed and replaced by #193 which is against the 2.x branch rather than master.

@briancullen
Copy link
Author

Hi @willarmiros

Given the comments made about breaking changes on the associated commit in the 2.x branch I’m surprised this has been reopened. Do we no longer have to wait for the major release?

@willarmiros
Copy link
Contributor

Hi @briancullen,

We have come to a release plan for a 3.0.0-alpha version of the SDK that will be released from the master branch. Since many of our customers want this and other 3.x changes ASAP, we want to expedite the release process even though we have more breaking changes coming. I am currently reviewing this PR and after giving some feedback hope to have it merged very soon.

We can't merge #193 since we want to keep the 2.x branch completely clear of breaking changes, since it still represents major version 2.x of the SDK. Stay tuned for a post on #157 that will explain the whole 3.0.0 release process.

Very sorry for the confusion, but we thank you very much for your continued contributions and look forward to releasing this soon.

Copy link
Contributor

@willarmiros willarmiros left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall great work, just some nitpicks and need for corresponding documentation. Thank you again for your contribution.

info: createLoggerForLevel('info'),
warn: createLoggerForLevel('warn'),
debug: createLoggerForLevel('debug'),
setLevel: (level) => logLevel = calculateLogLevel(level),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is convention in this SDK for environment variables to take precedence over properties set programmatically, so setLevel() should only modify the logging level if AWS_XRAY_DEBUG_MODE and AWS_XRAY_LOG_LEVEL are not set.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To take a step back, immediately after writing that set level method I kind of regretted it because I’m not entirely sure what the use case for it is. Particularly as the other methods are fairly comply implemented (take the winston logger for example) but setLevel isn’t.

So I suppose I’m asking do you think it is worth keeping?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that I can't really imagine a use case of needing to set the log level programmatically instead of with an EV. I have no issues with scrapping it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback. Given how late it is here I’ll update the code as requested and push up a new version on or before Monday morning. Have a nice weekend.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have removed the setLevel method as discussed so the environment variables are the only way to set the level of the logger.

var result = [], prop, i;
function formatLogMessage(level, message, meta) {
return createTimestamp() +' [' + level.toUpperCase() + '] ' +
(message !== undefined ? message : '') +
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check for truthiness of message instead of explicitly being equal to undefined. For example, with the current logger, logger.info(null) prints no message, whereas this logger prints out the string null.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed as requested.

var logger;
var xrayLogLevel = process.env.AWS_XRAY_LOG_LEVEL;
var validLogLevels = [ 'trace', 'debug', 'info', 'warn', 'error' ];
var logLevel = calculateLogLevel(process.env.AWS_XRAY_DEBUG_MODE ? 'debug' : process.env.AWS_XRAY_LOG_LEVEL);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you include the following changes to the readme in the core package:

  • Clarify in environment variables section that LOG_LEVEL is overridden by DEBUG_MODE
  • Include documentation for AWSXRay.getLogger().getLevel() and AWSXRay.getLogger().setLevel(level) APIs in the logging configuration section
  • Update the documentation for AWSXRay.setLogger(logger) to mention that using a third party logger can be incompatible with the SDK's logging environment variables (because, for example, setting a default winston logger will not print debug messages, even if AWS_XRAY_DEBUG_MODE is set)

Admittedly, some of these should already be in the docs but no better time than now to include them!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have updated the readme to reflect the logging changes. As the getLevel and setLevel methods have been removed they are not mentioned.

assert.equal(logger.getLogger().getLevel(), 'error');
});

it('Should set logging level after initialisation', function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test and below one should be changed to ensure programmatic changes to level do NOT override the values set by environment variables, once the change I suggested above is implemented.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As setLevel, and it's associated tests, has been removed this change no longer applies.

debug: createLoggerForLevel('debug'),
setLevel: (level) => logLevel = calculateLogLevel(level),
getLevel: () => validLogLevels[logLevel]
};

/* eslint-disable no-console */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and the other eslint comment at line 25 can be removed, seeing as the logger will now exclusively be performing logging with console methods. To prevent IDEs from complaining about console usage, please add the following line to the rules object (starting at line 8) in .eslintrc.json at the root of the package:

"no-console": "off",

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed as requested.

var format = require('date-fns/format');

var logger;
var xrayLogLevel = process.env.AWS_XRAY_LOG_LEVEL;
var validLogLevels = [ 'trace', 'debug', 'info', 'warn', 'error' ];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is trace included as a valid log level? It's not a method for logger and hasn't been in the past, so I'd recommend removing it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why I put trace there either. It has been removed.


var result = [], prop, i;
function formatLogMessage(level, message, meta) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lambda functions already include a timestamp and log level (assuming you use the appropriate console method) in their logging messages, so it is redundant to include that information again. For example, the code

AWSXRay.getLogger().error("This is an error msg");

would produce

2019-11-01T20:52:52.654Z d143da11-ec2e-4253-a561-8489348b442a ERROR 2019-11-01 20:52:52.595 +00:00 [ERROR] This is an error msg

I would recommend checking for the LAMBDA_TASK_ROOT environment variable and including a timestamp and log level based on that.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact that the time stamp is repeated for lambda did occur to me when I was writing this but won’t it be repeated for other things that write to cloudwatch as well? Say an ECS container for example?

At the time of writing I think I decided it was better to have a consistent log format that is produced regardless of the environment rather than trying to customise it for each different environment.

I’m happy to change it if that is the recommendation but, as I said, I don’t think this will avoid repeated timestamps in every situation.

An alternative could be to allow the user of the library to control the message format (either in total or just the inclusion of the time stamp) via another environment variable or api. I’m happy to prototype something along those lines if you want.

What do you think is the best approach?

Copy link
Contributor

@willarmiros willarmiros Nov 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think repeating the timestamp in CloudWatch is acceptable since CW treats their timestamp as a separate entity from the logging message, whereas Lambda actually interpolates the timestamp and log level into the logging message. I believe that is why the original author of the SDK special-cased logging in Lambda but not other environments.

If a user really cares about the logging format, they can always use the setLogger() API with their own logging object. So overall, I think omitting the timestamp and level in lambda environments is the best approach.

Copy link
Author

@briancullen briancullen Nov 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed so that if the LAMBDA_TASK_ROOT environment variable is set then the timestamp and logging level is not included in the outputted log line.

Brian Cullen added 4 commits November 3, 2019 16:33
This change removes the setLevel method so now only environment
variables can be used to set the log level.

It also changes how the log message is formatted so that if the
message is a falsey value it is replaced by an empty string.

Updated README to reflect the logging changes being made.

Finally a log level of silent is added which prevents all logging.
Change to check an environment variable to determine if the code
is running within the context of an AWS lambda. If it is then the
standard logger will not add the timestamp or the logging level to
the logging output, rather this is left to the lambda runtime.
@briancullen
Copy link
Author

Hello @willarmiros,

Think I addressed all the issues that you raised but let me know if I missed anything.

Apart from that if you do consider changing the log format to be a breaking change I suppose the last thin I'd like to check is that you are happy with the format of the logs produced particularly those that have metadata? Currently in the sdk code I think it is only stack traces you pass as metadata.

Filter so that only lines with a message or metadata are actually
output from the logger. Without this you could end up with lines that
only consist of a timestamp or, in the case of Lambda, nothing at all.
Copy link
Contributor

@willarmiros willarmiros left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All necessary changes have been made. The metadata is being formatted in the same way as it was previously except with some more validation, so that is fine. Approving this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants