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

feat: emit all shell logging to publishProgressListener #295

Merged
merged 29 commits into from
Jan 21, 2025

Conversation

HBobertz
Copy link
Contributor

@HBobertz HBobertz commented Jan 9, 2025

Closes #196

Removes quiet flag and also ensures all events are routed to the progressListener.

removeD the existing logger callback and replaces it with shellEventPublisher which will route the message back to the configured progressListener if configured. The default behavior is stdio for the new subprocessOutputDestination option, which essentially is the old behavior. Where shells write directly to stdout/stderr

bin/publish.ts Outdated Show resolved Hide resolved
@HBobertz HBobertz marked this pull request as ready for review January 9, 2025 23:05
bin/logging.ts Outdated Show resolved Hide resolved
lib/private/handlers/container-images.ts Outdated Show resolved Hide resolved
lib/private/shell.ts Outdated Show resolved Hide resolved
lib/private/shell.ts Outdated Show resolved Hide resolved
lib/progress.ts Outdated Show resolved Hide resolved
test/mock-progress-listener.ts Outdated Show resolved Hide resolved
lib/private/handlers/files.ts Outdated Show resolved Hide resolved
bin/publish.ts Outdated Show resolved Hide resolved
lib/progress.ts Outdated Show resolved Hide resolved
lib/progress.ts Outdated Show resolved Hide resolved
bin/logging.ts Outdated Show resolved Hide resolved
bin/publish.ts Outdated Show resolved Hide resolved
lib/private/asset-handler.ts Outdated Show resolved Hide resolved
lib/private/shell.ts Show resolved Hide resolved
lib/progress.ts Show resolved Hide resolved
lib/private/shell.ts Outdated Show resolved Hide resolved
lib/private/shell.ts Outdated Show resolved Hide resolved
@@ -0,0 +1,67 @@
import { LogLevel } from '../bin/logging';
Copy link
Contributor

Choose a reason for hiding this comment

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

Noooooooo

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Noooooooo

😂 😂 😂

Copy link
Contributor

Choose a reason for hiding this comment

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

I still feel this export shouldn't exist. I guess you didn't write it, so I can't fault you for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can you explain further why this is bad? I get that generally speaking it's bad to export stuff from bin just on the principle that it's mean to be the executable and thus only ever consumes stuff. But it seems valid to me to export from bin for testing purposes

Copy link
Contributor

Choose a reason for hiding this comment

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

It's that. bin is not intended to be library, so it shouldn't be used as a library.

Maybe it is justifiable if this MockProgressListener is intended to be used to test exclusively one of the CLI tools, but I don't think it is. And even then, if the logic in that CLI tools is complex and interesting enough to warrant testing, it's probably interesting enough to lift it into the lib directory wholesale.

@rix0rrr rix0rrr changed the title chore: emit all shell logging to publishProgressListener feat: emit all shell logging to publishProgressListener Jan 13, 2025
lib/private/docker-credentials.ts Outdated Show resolved Hide resolved
lib/private/handlers/container-images.ts Outdated Show resolved Hide resolved
lib/private/shell.ts Outdated Show resolved Hide resolved
break;
case 'stdio':
default:
if (eventType != 'data_stderr') {
Copy link
Contributor

Choose a reason for hiding this comment

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

This now would print the command line as well, but the old code didn't use to do that. I think you only want to print for data_* events.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It printed the open but you're right about the close being my own design so I'm gonna make sure I ignore that one.

Copy link
Contributor

@rix0rrr rix0rrr Jan 14, 2025

Choose a reason for hiding this comment

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

It sent the command line to the logger (as opposed to the stdout and stderr chunks, which always got written to stdio immediately). Did the logger always send it to stdout?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I fixed this yeah the only things that went to stdout was the shell stdout. That is supposed to go to stderr, good catch

Copy link
Contributor

Choose a reason for hiding this comment

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

It shouldn't go to stderr either I don't think. See my bigger comment down below.

lib/progress.ts Show resolved Hide resolved
lib/progress.ts Show resolved Hide resolved
lib/private/docker.ts Outdated Show resolved Hide resolved
lib/private/docker.ts Outdated Show resolved Hide resolved
lib/private/handlers/container-images.ts Outdated Show resolved Hide resolved
lib/private/handlers/container-images.ts Show resolved Hide resolved
Copy link
Contributor

@rix0rrr rix0rrr left a comment

Choose a reason for hiding this comment

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

Almost there!

lib/private/docker.ts Outdated Show resolved Hide resolved
lib/private/docker.ts Outdated Show resolved Hide resolved
Comment on lines 252 to 262
const docker = new Docker(options.logger);
const docker = new Docker(options.eventEmitter);
Copy link
Contributor

Choose a reason for hiding this comment

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

In your mind, is this code churn worth it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🤷‍♂️ I didn't like the name logger since log to me means "print to stdout/stderr" and that's not always true anymore

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess this us ascribing different meanings to words. You interpret "logger" to mean "the thing that prints messages to stdio" and I interpret logger to mean "the thing that receives messages and does something with them". Could be printing, could be writing to a file, could be sending over HTTP to a syslog daemon or to CloudWatch.

Copy link
Contributor

Choose a reason for hiding this comment

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

Strictly speaking, the thing you're passing right now is not an event emitter, but rather an event receiver 😛

lib/private/docker.ts Outdated Show resolved Hide resolved
lib/private/handlers/container-images.ts Outdated Show resolved Hide resolved
break;
case 'stdio':
default:
if (eventType == 'data_stdout' || eventType == 'open') {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm still not convinced that the open event used to be sent to stdout in the old code.

How sure are you about that?

Copy link
Contributor Author

@HBobertz HBobertz Jan 20, 2025

Choose a reason for hiding this comment

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

good catch, it went to stderr

Copy link
Contributor

Choose a reason for hiding this comment

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

It went nowhere I'm pretty sure?

Copy link
Contributor

@rix0rrr rix0rrr left a comment

Choose a reason for hiding this comment

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

Almost almost there. This is Zeno's request changes 😉

lib/private/docker.ts Outdated Show resolved Hide resolved
Comment on lines 209 to 212
const shellEventPublisher = (event: ShellEventType, message: string) => {
const eventType = shellEventToEventType(event);
this.eventEmitter(eventType, message);
};
Copy link
Contributor

Choose a reason for hiding this comment

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

👨‍🍳💋👌

lib/private/docker.ts Outdated Show resolved Hide resolved
Comment on lines 206 to 209
const shellEventPublisher = (event: ShellEventType, message: string) => {
const eventType = shellEventToEventType(event);
this.host.emitMessage(eventType, message);
};
Copy link
Contributor

Choose a reason for hiding this comment

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

💅 I see this being repeated a couple of times.

In principle it's not too bad, and I'm fine with leaving it this way. We could also make it slightly nicer by packaging that logic up and putting it in a single place:

/**
 * Create a ShellEventPublisher for an IHandlerHost
 *
 * Returns a ShellEventPublisher that translates ShellEvents into messages
 * emitted via the HandlerHost. Uses `shellEventToEventType` to translate
 * shell event types to HandlerHost event types.
 */
function makeHandlerHostEventPublisher(host: IEventHost) {
  return (event: ShellEventType, message: string) => {
      const eventType = shellEventToEventType(event);
      this.host.emitMessage(eventType, message);
    };
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

if you took the time to write this with a tsdoc I'll put it in lol

Copy link
Contributor Author

Choose a reason for hiding this comment

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

changed this up a bit because it takes an event emitter but still

default:
if (shellEventType == 'data_stdout') {
process.stdout.write(chunk);
} else if (shellEventType == 'data_stderr' || shellEventType == 'open') {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm still not convinced this is in line with old behavior.

My take

The old code used to do:

options.logger(renderCommandLine(command));

So the command line (in your case, the open event) would get sent into the logger exclusively. The only place I can find that options.logger gets a value is like this (via a small detour on Docker object):

    const dockerForPushing = await this.host.dockerFactory.forEcrPush({
      repoUri: initOnce.repoUri,
      logger: (m: string) => this.host.emitMessage(EventType.DEBUG, m),
      ecr: initOnce.ecr,
    });

So the command line didn't use to go to stderr, it got emitted as a DEBUG event over the handler progress protocol.

Your take

You seem pretty convinced that in the old code the commandline used to go to stdout or stderr. Can you point me to the chain of calls that leads to that happening?

Copy link
Contributor Author

@HBobertz HBobertz Jan 21, 2025

Choose a reason for hiding this comment

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

Yeah you're right here, when I was thinking about this I was thinking about stdio being the "I'm using this from the CLI option" where this would get emitted to stderr from the console progress listener which prints to sdterr, so might as well handle it here and keep every congruent. However there will be a brief time where the cdk is using stdio before we swap it over to passing publish and so I have to make it backwards compatible there. So yeah went ahead and changed it so it always emits the event on open

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah I see what you're concerned about. I don't really care about what the cdk-assets CLI does. I care a lot more about what the interface to the CDK CLI does.

(But if we do the same thing across the library protocol, I feel like we can't help but do the same thing for the cdk-assets CLI as well...?)

lib/progress.ts Outdated
Comment on lines 98 to 101
case 'data_stdout':
return EventType.SHELL_DATA;
case 'data_stderr':
return EventType.SHELL_DATA;
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we lose the ability to tell whether it's stdout or stderr data? I would think that's a rather important distinction for consumers...?

(Sorry I didn't pick up on this before)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah since this part is new I honestly figured that it wouldn't be relevant to distinguish between the 2 but I can always break it out in to shell_stderr and shell_stdout if we want

Copy link
Contributor Author

Choose a reason for hiding this comment

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

went ahead and did that

type,
message: event.message,
stream: ['open', 'data_stdout', 'close'].includes(type) ? 'stdout' : 'stderr',
level,
Copy link
Contributor

Choose a reason for hiding this comment

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

Where is level used?

(And if level isn't used, EVENT_TO_LEVEL isn't used, and if EVENT_TO_LEVEL isn't used, you don't need the import of LogLevel).

Copy link
Contributor

Choose a reason for hiding this comment

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

I can see you have unused symbols in this file. For some reason, the linter setup of this repo doesn't fail on unused imports and unused globals... but this will fail the build once we move this code to a repo with a stricter linter setup.

Can you have a look around and remove variables that have a slightly dimmer color, to indicate they are unused?

image

Either that, or configure eslint to complain about them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah removed all this though I feel like it may be useful later, we can just add it then

@HBobertz HBobertz requested a review from rix0rrr January 21, 2025 14:33
@aws-cdk-automation aws-cdk-automation added this pull request to the merge queue Jan 21, 2025
Merged via the queue into main with commit 6877039 Jan 21, 2025
7 checks passed
@aws-cdk-automation aws-cdk-automation deleted the bobertzh/shell-log-capture branch January 21, 2025 16:01
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.

All CDK-Assets logging needs to be pluggable
3 participants