-
Notifications
You must be signed in to change notification settings - Fork 4k
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
chore(cli): use CliIoHost as logger everywhere #32708
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pull request linter has failed. See the aws-cdk-automation comment below for failure reasons. If you believe this pull request should receive an exemption, please comment and provide a justification.
A comment requesting an exemption should contain the text Exemption Request
. Additionally, if clarification is needed add Clarification Request
to a comment.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #32708 +/- ##
==========================================
+ Coverage 66.96% 67.02% +0.05%
==========================================
Files 329 330 +1
Lines 18667 18683 +16
Branches 3260 3255 -5
==========================================
+ Hits 12501 12522 +21
+ Misses 5839 5833 -6
- Partials 327 328 +1
Flags with carried forward coverage won't be shown. Click here to find out more.
|
➡️ PR build request submitted to A maintainer must now check the pipeline and add the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i haven't looked at everything, mainly the tests, but providing some initial feedback and will review fully tmr
packages/aws-cdk/lib/cdk-toolkit.ts
Outdated
@@ -601,7 +601,7 @@ export class CdkToolkit { | |||
anyRollbackable = true; | |||
} | |||
const elapsedRollbackTime = new Date().getTime() - startRollbackTime; | |||
print('\n✨ Rollback time: %ss\n', formatTime(elapsedRollbackTime)); | |||
print('\n✨ Rollback time: %ss\n', formatTime(elapsedRollbackTime).toString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're going away from the %ss
, which i support, we should do that here too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually people can still do %s. This is actually just a good catch that I don't need to do .toString anymore. It was previously more important.
logBuffer.splice(0); | ||
} | ||
} | ||
} | ||
|
||
interface LogOptions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all these should be readonly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bumping this unless you disagree
throw new Error(`Invalid message code: ${options.code}`); | ||
} | ||
} else { | ||
options.code = `TOOLKIT_${Math.min(levelPriority[options.level] - 1, 2)}000`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did we decide on this way of leveling here? and i agree with codecov on this one, should be tested
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
feels odd that we would have one system of 1-4, and another system of 0-2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bumping this
* All 'error' level message codes begin with 0. | ||
* All warning level message codes begin with 1. | ||
* All info level message codes begin with 2. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* All 'error' level message codes begin with 0. | |
* All warning level message codes begin with 1. | |
* All info level message codes begin with 2. | |
* All 'error' level message codes begin with 0. | |
* All 'warning' level message codes begin with 1. | |
* All 'info' level message codes begin with 2. |
/** | ||
* Whether the CliIoHost is running in CI mode. In CI mode, all non-error output goes to stdout instead of stderr. | ||
*/ | ||
private ci: boolean = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm not against this style, but i would like how you add defaults to ci
and isTTY
to be the same...
case 'debug': | ||
case 'trace': | ||
return levelNum === 2; | ||
default: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be no need for default if you get all the levels
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You never know what someone is gonna add and forget to modify in the validation function 😅
* @param level The IoMessageLevel of the message | ||
* @returns boolean indicating if the code is valid for the given level | ||
*/ | ||
export function validateMessageCode(code: string, level?: IoMessageLevel): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i would prefer this function return not just a true/false but information on why/what the errors are. usually achieved by returning a list of errors, with []
indicating "no error"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eh maybe, either way I'll refactor this into something after we confirm how exactly we want message codes to look. Might just throw errors tbh
* All 'error' level message codes begin with 0. | ||
* All warning level message codes begin with 1. | ||
* All info level message codes begin with 2. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I think it'd be nicer to use letters for this: E
, W
, I
. But that's a bit of bikeshedding.
* 'ASSETS_2000' // valid cdk-assets info message with generic info code _2000 | ||
* 'TOOLKIT_0002' // valid toolkit error message with specific error code _0002 | ||
* 'SDK_1023' // valid sdk warning message with specific warning code _1023 | ||
* 'sdk_0001' // invalid: lowercase | ||
* 'TOOLKIT-0001' // invalid: invalid separator | ||
* 'SDK_3000' // invalid: all message codes must be between 0000 and 2999 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we work CDK
into some of the categories in some way? CDKTOOLKIT_0002
or CT0002
for short or something?
By the way, I would say that if you clearly define the format, you don't need to show counterexamples of all the things it cannot be.
A code is for the format
<XX>_<L><yyy>
, where:
<XX>
is a category code, and must be one ofCA
,CT,
SDK
.<L>
indicates a severity level, one ofE
,W
,I
,D
,T
.<yyy>
is a 3 digit code indicating the source of the message. The code is either000
if this is a nonspecific log message, or a specific code unique within its category to indicate a specific type of message.
If you specify the "grammar" of error codes this way, there's no need to say "it can't be sdk-11
" because that will be implicitly disallowed by the grammar already.
Define constants for the categories and codes somewhere.
@@ -21,7 +21,21 @@ interface IoMessage { | |||
readonly action: IoAction; | |||
|
|||
/** | |||
* A short code uniquely identifying message type. | |||
* A short message code uniquely identifying a message type of the format [CATEGORY]_[NUMBER_CODE]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you have a look at how JSII emits messages? Not saying we should do exactly the same - I think this proposal actually adds some enhancements over it, but its a good resource to look at.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't really check it out and just started fresh. But if we want to incorporate that into the number system that's fine with me
* All warning level message codes begin with 1. | ||
* All info level message codes begin with 2. | ||
* | ||
* Codes ending in 000 are generic messages, while codes ending in 001-999 are specific to a particular message. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't fully understand the need for this. Isn't every code attached to a particular message?
Can you show an example of both authoring and consuming different codes here?
I feel like we can just say that we have 3 digits to denote the message and thats it, without the special handling of 000
. Also having a generic code might eventually result in a graveyard (though not having it will bloat up the numbers).
We can also start without 000
. That is, start with 001...999
and add 000
as a "generic" thing if we need it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Every message will have a code but they do not need to be a unique code. I fully suspect that especially for info
level codes that people really won't care to differentiate as much as they would with warnings or errors. I suspect any arbitrary log message today that is like "doing , please wait" probably doesn't warrant a code so it'll be a generic info code. The alternative is that code becomes an optional value (which is probably fine), and is really only relevant for errors and warnings
Co-authored-by: Kaizen Conroy <[email protected]>
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Read through all the files. I'm a bit concerned as to whether or not we're ok with changing the printed messages in this PR. If we are not aiming to do that, then we really need to scrutinize the tests and the diff makes that very difficult to do :). So I haven't done that yet unless it's really necessary.
logBuffer.splice(0); | ||
} | ||
} | ||
} | ||
|
||
interface LogOptions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bumping this unless you disagree
throw new Error(`Invalid message code: ${options.code}`); | ||
} | ||
} else { | ||
options.code = `TOOLKIT_${Math.min(levelPriority[options.level] - 1, 2)}000`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bumping this
...args: unknown[] | ||
): void { | ||
// Extract message and code from input | ||
const { message, code = `TOOLKIT_${getCodeLevel(level)}000` } = typeof input === 'object' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i believe you're going to update to include CDK
prefix. but also, this and line 94 both hardcode the syntax. it should live in one place so that if for whatever reason we need to change it we don't have to do it twice
} | ||
|
||
// Type for the object parameter style | ||
interface LogParams { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
readonly
}; | ||
|
||
/** Alias for the {@link info} logging function */ | ||
export const print = info; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why can't we just use info
everywhere that print
is being used?
@@ -151,7 +151,7 @@ function v3ProviderFromV2Credentials(x: SDKv2CompatibleCredentials): AwsCredenti | |||
function refreshFromPluginProvider(current: AwsCredentialIdentity, producer: () => Promise<PluginProviderResult>): AwsCredentialIdentityProvider { | |||
return async () => { | |||
// eslint-disable-next-line no-console | |||
console.error(current, Date.now()); | |||
info(format(current), Date.now()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should remove the // eslint-disable-next-line no-console
on this any any other instances where you no longer call the console
.
@@ -514,7 +515,7 @@ export class HistoryActivityPrinter extends ActivityPrinterBase { | |||
public stop() { | |||
// Print failures at the end | |||
if (this.failures.length > 0) { | |||
this.stream.write('\nFailed resources:\n'); | |||
info('\nFailed resources:'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in this file, multiple classes hold a this.stream
property to determine if it writes to stdout
or stderr
. with your change, this property seems obsolete -- we are no longer storing information on what stream to write to on these printers. if that is correct, we should remove that property altogether so as not to leave unused properties behind
util.format( | ||
'%s | %s%s | %s | %s | %s %s%s%s\n', | ||
'%s | %s%s | %s | %s | %s %s%s%s', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why remove newline? and specifically, is the goal of this PR to not change printing output at all? how are you verifying that
|
||
if (stackCollection.stackCount === 0) { | ||
// eslint-disable-next-line no-console | ||
console.error('No stacks selected'); | ||
error('No stacks selected'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove eslint comment above. please find all the other instances, i'm not going to comment on them all.
@@ -56,7 +56,7 @@ export async function contextHandler(options: ContextOptions): Promise<number> { | |||
if (options.json) { | |||
/* istanbul ignore next */ | |||
const contextValues = options.context.all; | |||
process.stdout.write(JSON.stringify(contextValues, undefined, 2)); | |||
info(JSON.stringify(contextValues, undefined, 2)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wont info
write to stderr
?
The pull request linter fails with the following errors:
PRs must pass status checks before we can provide a meaningful review. If you would like to request an exemption from the status checks or clarification on feedback, please leave a comment on this PR containing |
Related to #32346
Reason for this change
Capture all logs across the CLI as IoMessages so that when we allow customers to use the CDK Core functionality programmatically, these logs are delivered to the customers as messages and now just swallowed across the CLI.
Description of changes
Prevented access to
log()
andformatLogMessage()
. Now the only ways to log something properly are either through the exported log functions (which is how everyone was doing it anyway), or throughCliIoHost.notify()
directly.CliIoHost is now exposed as a global singleton which is currently only directly exclusively used in
logging.ts
but is effectively used everywhere as all logging functions inevitably callCliIoHost.notify()
All logging functions now optionally support the following input types
and everything is now translated into an
IoMessage
and callsCliIoHost.notify()
from these logging functions. Nothing currently specifies any message code so it's all the generic _0000, _1000, _2000Description of how you validated changes
added and updated unit tests
Checklist
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license