[ VM / CLI ] Add --verbosity to VM options

The verbosity option allows for specifying the CFE output verbosity

Fixes https://github.com/dart-lang/sdk/issues/44727

TEST=existing tests compile_test.dart and run_test.dart have new tests

Change-Id: I3d4e50811f84650aacf774ddb370a6eb765b9b24
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/181100
Commit-Queue: Siva Annamalai <asiva@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
diff --git a/pkg/dartdev/lib/src/commands/compile.dart b/pkg/dartdev/lib/src/commands/compile.dart
index f3f6e63..021db07 100644
--- a/pkg/dartdev/lib/src/commands/compile.dart
+++ b/pkg/dartdev/lib/src/commands/compile.dart
@@ -157,7 +157,16 @@
         commonOptions['outputFile'].flag,
         help: commonOptions['outputFile'].help,
         abbr: commonOptions['outputFile'].abbr,
+      )
+      ..addOption(
+        commonOptions['verbosity'].flag,
+        help: commonOptions['verbosity'].help,
+        abbr: commonOptions['verbosity'].abbr,
+        defaultsTo: commonOptions['verbosity'].defaultsTo,
+        allowed: commonOptions['verbosity'].allowed,
+        allowedHelp: commonOptions['verbosity'].allowedHelp,
       );
+
     addExperimentalFlags(argParser, verbose);
   }
 
@@ -189,6 +198,10 @@
     List<String> args = [];
     args.add('--snapshot-kind=$formatName');
     args.add('--snapshot=${path.canonicalize(outputFile)}');
+
+    String verbosity = argResults[commonOptions['verbosity'].flag];
+    args.add('--verbosity=$verbosity');
+
     if (enabledExperiments.isNotEmpty) {
       args.add("--enable-experiment=${enabledExperiments.join(',')}");
     }
diff --git a/pkg/dartdev/lib/src/commands/run.dart b/pkg/dartdev/lib/src/commands/run.dart
index 80ca891..2825b49 100644
--- a/pkg/dartdev/lib/src/commands/run.dart
+++ b/pkg/dartdev/lib/src/commands/run.dart
@@ -8,6 +8,8 @@
 import 'dart:io';
 
 import 'package:args/args.dart';
+import 'package:front_end/src/api_prototype/compiler_options.dart'
+    show Verbosity;
 import 'package:path/path.dart';
 import 'package:pub/pub.dart';
 
@@ -91,6 +93,13 @@
       ..addFlag(
         'enable-asserts',
         help: 'Enable assert statements.',
+      )
+      ..addOption(
+        'verbosity',
+        help: 'Sets the verbosity level of the compilation.',
+        defaultsTo: Verbosity.defaultValue,
+        allowed: Verbosity.allowedValues,
+        allowedHelp: Verbosity.allowedValuesHelp,
       );
 
     if (verbose) {
diff --git a/pkg/dartdev/test/commands/compile_test.dart b/pkg/dartdev/test/commands/compile_test.dart
index 5aaf14c..61ebc76 100644
--- a/pkg/dartdev/test/commands/compile_test.dart
+++ b/pkg/dartdev/test/commands/compile_test.dart
@@ -236,7 +236,7 @@
         reason: 'File not found: $outFile');
   });
 
-  test('Compile exe with warning', () {
+  test('Compile exe with warnings', () {
     final p = project(mainSrc: '''
 void main() {
   int i = 0;
@@ -334,6 +334,33 @@
         reason: 'File not found: $outFile');
   });
 
+  test('Compile exe without warnings', () {
+    final p = project(mainSrc: '''
+void main() {
+  int i = 0;
+  i?.isEven;
+}
+''');
+    final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+    final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
+
+    var result = p.runSync(
+      [
+        'compile',
+        'exe',
+        '--verbosity=error',
+        '-o',
+        outFile,
+        inFile,
+      ],
+    );
+
+    expect(result.stdout,
+        predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+    expect(result.stderr, isEmpty);
+    expect(result.exitCode, 0);
+  });
+
   test('Compile JS with sound null safety', () {
     final p = project(mainSrc: '''void main() {}''');
     final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
@@ -405,6 +432,33 @@
         reason: 'File not found: $outFile');
   });
 
+  test('Compile JS without warnings', () {
+    final p = project(mainSrc: '''
+void main() {
+  int i = 0;
+  i?.isEven;
+}
+''');
+    final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+    final outFile = path.canonicalize(path.join(p.dirPath, 'myjs'));
+
+    var result = p.runSync(
+      [
+        'compile',
+        'js',
+        '--verbosity=error',
+        '-o',
+        outFile,
+        inFile,
+      ],
+    );
+
+    expect(result.stdout,
+        predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+    expect(result.stderr, isEmpty);
+    expect(result.exitCode, 0);
+  });
+
   test('Compile AOT snapshot with sound null safety', () {
     final p = project(mainSrc: '''void main() {}''');
     final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
@@ -476,6 +530,61 @@
         reason: 'File not found: $outFile');
   });
 
+  test('Compile AOT snapshot without warnings', () {
+    final p = project(mainSrc: '''
+void main() {
+  int i = 0;
+  i?.isEven;
+}
+''');
+    final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+    final outFile = path.canonicalize(path.join(p.dirPath, 'myaot'));
+
+    var result = p.runSync(
+      [
+        'compile',
+        'aot-snapshot',
+        '--verbosity=error',
+        '-o',
+        outFile,
+        inFile,
+      ],
+    );
+
+    expect(result.stdout,
+        predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+    expect(result.stderr, isEmpty);
+    expect(result.exitCode, 0);
+  });
+
+  test('Compile AOT snapshot with warnings', () {
+    final p = project(mainSrc: '''
+void main() {
+  int i = 0;
+  i?.isEven;
+}
+''');
+    final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+    final outFile = path.canonicalize(path.join(p.dirPath, 'myaot'));
+
+    var result = p.runSync(
+      [
+        'compile',
+        'aot-snapshot',
+        '--verbosity=warning',
+        '-o',
+        outFile,
+        inFile,
+      ],
+    );
+
+    expect(result.stdout,
+        predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+    expect(result.stdout, contains('Warning: '));
+    expect(result.stderr, isEmpty);
+    expect(result.exitCode, 0);
+  });
+
   test('Compile kernel with sound null safety', () {
     final p = project(mainSrc: '''void main() {}''');
     final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
@@ -523,6 +632,82 @@
         reason: 'File not found: $outFile');
   });
 
+  test('Compile kernel without info', () {
+    final p = project(mainSrc: '''void main() {}''');
+    final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+    final outFile = path.canonicalize(path.join(p.dirPath, 'mydill'));
+
+    var result = p.runSync(
+      [
+        'compile',
+        'kernel',
+        '--verbosity=warning',
+        '-o',
+        outFile,
+        inFile,
+      ],
+    );
+
+    expect(result.stdout,
+        predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+    expect(result.stderr, isEmpty);
+    expect(result.exitCode, 0);
+    expect(File(outFile).existsSync(), true,
+        reason: 'File not found: $outFile');
+  });
+
+  test('Compile kernel without warning', () {
+    final p = project(mainSrc: '''
+void main() {
+    int i;
+    i?.isEven;
+}''');
+    final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+    final outFile = path.canonicalize(path.join(p.dirPath, 'mydill'));
+
+    var result = p.runSync(
+      [
+        'compile',
+        'kernel',
+        '--verbosity=error',
+        '-o',
+        outFile,
+        inFile,
+      ],
+    );
+
+    expect(result.stdout,
+        predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+    expect(result.stderr, contains('must be assigned before it can be used'));
+    expect(result.exitCode, 254);
+  });
+
+  test('Compile kernel with warnings', () {
+    final p = project(mainSrc: '''
+void main() {
+    int i = 0;
+    i?.isEven;
+}''');
+    final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+    final outFile = path.canonicalize(path.join(p.dirPath, 'mydill'));
+
+    var result = p.runSync(
+      [
+        'compile',
+        'kernel',
+        '--verbosity=warning',
+        '-o',
+        outFile,
+        inFile,
+      ],
+    );
+
+    expect(result.stdout,
+        predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+    expect(result.stderr, contains('Warning:'));
+    expect(result.exitCode, 0);
+  });
+
   test('Compile JIT snapshot with sound null safety', () {
     final p = project(mainSrc: '''void main() {}''');
     final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
@@ -569,4 +754,80 @@
     expect(File(outFile).existsSync(), true,
         reason: 'File not found: $outFile');
   });
+
+  test('Compile JIT snapshot without info', () {
+    final p = project(mainSrc: '''void main() {}''');
+    final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+    final outFile = path.canonicalize(path.join(p.dirPath, 'myjit'));
+
+    var result = p.runSync(
+      [
+        'compile',
+        'jit-snapshot',
+        '--verbosity=warning',
+        '-o',
+        outFile,
+        inFile,
+      ],
+    );
+
+    expect(result.stdout,
+        predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+    expect(result.stderr, isEmpty);
+    expect(result.exitCode, 0);
+    expect(File(outFile).existsSync(), true,
+        reason: 'File not found: $outFile');
+  });
+
+  test('Compile JIT snapshot without warnings', () {
+    final p = project(mainSrc: '''
+void main() {
+    int i;
+    i?.isEven;
+}''');
+    final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+    final outFile = path.canonicalize(path.join(p.dirPath, 'myjit'));
+
+    var result = p.runSync(
+      [
+        'compile',
+        'jit-snapshot',
+        '--verbosity=error',
+        '-o',
+        outFile,
+        inFile,
+      ],
+    );
+
+    expect(result.stdout,
+        predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+    expect(result.stderr, contains('must be assigned before it can be used'));
+    expect(result.exitCode, 254);
+  });
+
+  test('Compile JIT snapshot with warnings', () {
+    final p = project(mainSrc: '''
+void main() {
+    int i = 0;
+    i?.isEven;
+}''');
+    final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+    final outFile = path.canonicalize(path.join(p.dirPath, 'myjit'));
+
+    var result = p.runSync(
+      [
+        'compile',
+        'jit-snapshot',
+        '--verbosity=warning',
+        '-o',
+        outFile,
+        inFile,
+      ],
+    );
+
+    expect(result.stdout,
+        predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+    expect(result.stderr, contains('Warning:'));
+    expect(result.exitCode, 0);
+  });
 }
diff --git a/pkg/dartdev/test/commands/run_test.dart b/pkg/dartdev/test/commands/run_test.dart
index 59bffba..12c07d3 100644
--- a/pkg/dartdev/test/commands/run_test.dart
+++ b/pkg/dartdev/test/commands/run_test.dart
@@ -9,6 +9,8 @@
 
 import '../utils.dart';
 
+const String soundNullSafetyMessage = 'Info: Compiling with sound null safety';
+
 void main() {
   group('run', run, timeout: longTimeout);
 }
@@ -279,4 +281,21 @@
     expect(result.stderr, isEmpty);
     expect(result.exitCode, 0);
   });
+
+  test('without verbose CFE info', () {
+    final p = project(mainSrc: '''void main() {}''');
+
+    var result = p.runSync(
+      [
+        'run',
+        '--verbosity=warning',
+        p.relativeFilePath,
+      ],
+    );
+
+    expect(result.stdout,
+        predicate((o) => !'$o'.contains(soundNullSafetyMessage)));
+    expect(result.stderr, isEmpty);
+    expect(result.exitCode, 0);
+  });
 }
diff --git a/pkg/vm/bin/kernel_service.dart b/pkg/vm/bin/kernel_service.dart
index 2a57c7b..a558085 100644
--- a/pkg/vm/bin/kernel_service.dart
+++ b/pkg/vm/bin/kernel_service.dart
@@ -89,7 +89,6 @@
 CompilerOptions setupCompilerOptions(
     FileSystem fileSystem,
     Uri platformKernelPath,
-    bool suppressWarnings,
     bool enableAsserts,
     int nullSafety,
     List<String> experimentalFlags,
@@ -132,10 +131,10 @@
           errors.addAll(message.plainTextFormatted);
           break;
         case Severity.warning:
-          printToStdErr = !suppressWarnings;
+          printToStdErr = true;
           break;
         case Severity.info:
-          printToStdOut = !suppressWarnings;
+          printToStdOut = true;
           break;
         case Severity.context:
         case Severity.ignored:
@@ -157,7 +156,6 @@
   final int isolateId;
   final FileSystem fileSystem;
   final Uri platformKernelPath;
-  final bool suppressWarnings;
   final bool enableAsserts;
   final int nullSafety;
   final List<String> experimentalFlags;
@@ -175,8 +173,7 @@
   CompilerOptions options;
 
   Compiler(this.isolateId, this.fileSystem, this.platformKernelPath,
-      {this.suppressWarnings: false,
-      this.enableAsserts: false,
+      {this.enableAsserts: false,
       this.nullSafety: kNullSafetyOptionUnspecified,
       this.experimentalFlags: null,
       this.supportCodeCoverage: false,
@@ -201,7 +198,6 @@
     options = setupCompilerOptions(
         fileSystem,
         platformKernelPath,
-        suppressWarnings,
         enableAsserts,
         nullSafety,
         experimentalFlags,
@@ -294,15 +290,13 @@
 
   IncrementalCompilerWrapper(
       int isolateId, FileSystem fileSystem, Uri platformKernelPath,
-      {bool suppressWarnings: false,
-      bool enableAsserts: false,
+      {bool enableAsserts: false,
       int nullSafety: kNullSafetyOptionUnspecified,
       List<String> experimentalFlags: null,
       String packageConfig: null,
       String invocationModes: '',
       String verbosityLevel: Verbosity.defaultValue})
       : super(isolateId, fileSystem, platformKernelPath,
-            suppressWarnings: suppressWarnings,
             enableAsserts: enableAsserts,
             nullSafety: nullSafety,
             experimentalFlags: experimentalFlags,
@@ -317,14 +311,12 @@
       int isolateId,
       FileSystem fileSystem,
       Uri platformKernelPath,
-      {bool suppressWarnings: false,
-      bool enableAsserts: false,
+      {bool enableAsserts: false,
       List<String> experimentalFlags: null,
       String packageConfig: null,
       String invocationModes: ''}) {
     IncrementalCompilerWrapper result = IncrementalCompilerWrapper(
         isolateId, fileSystem, platformKernelPath,
-        suppressWarnings: suppressWarnings,
         enableAsserts: enableAsserts,
         experimentalFlags: experimentalFlags,
         packageConfig: packageConfig,
@@ -353,7 +345,6 @@
   Future<IncrementalCompilerWrapper> clone(int isolateId) async {
     IncrementalCompilerWrapper clone = IncrementalCompilerWrapper(
         isolateId, fileSystem, platformKernelPath,
-        suppressWarnings: suppressWarnings,
         enableAsserts: enableAsserts,
         nullSafety: nullSafety,
         experimentalFlags: experimentalFlags,
@@ -384,7 +375,6 @@
   SingleShotCompilerWrapper(
       int isolateId, FileSystem fileSystem, Uri platformKernelPath,
       {this.requireMain: false,
-      bool suppressWarnings: false,
       bool enableAsserts: false,
       int nullSafety: kNullSafetyOptionUnspecified,
       List<String> experimentalFlags: null,
@@ -392,7 +382,6 @@
       String invocationModes: '',
       String verbosityLevel: Verbosity.defaultValue})
       : super(isolateId, fileSystem, platformKernelPath,
-            suppressWarnings: suppressWarnings,
             enableAsserts: enableAsserts,
             nullSafety: nullSafety,
             experimentalFlags: experimentalFlags,
@@ -428,8 +417,7 @@
 
 Future<Compiler> lookupOrBuildNewIncrementalCompiler(int isolateId,
     List sourceFiles, Uri platformKernelPath, List<int> platformKernel,
-    {bool suppressWarnings: false,
-    bool enableAsserts: false,
+    {bool enableAsserts: false,
     int nullSafety: kNullSafetyOptionUnspecified,
     List<String> experimentalFlags: null,
     String packageConfig: null,
@@ -461,7 +449,6 @@
       // isolate was shut down. Message should be handled here in this script.
       compiler = new IncrementalCompilerWrapper(
           isolateId, fileSystem, platformKernelPath,
-          suppressWarnings: suppressWarnings,
           enableAsserts: enableAsserts,
           nullSafety: nullSafety,
           experimentalFlags: experimentalFlags,
@@ -516,10 +503,9 @@
   final bool isStatic = request[9];
   final List dillData = request[10];
   final int blobLoadCount = request[11];
-  final bool suppressWarnings = request[12];
-  final bool enableAsserts = request[13];
+  final bool enableAsserts = request[12];
   final List<String> experimentalFlags =
-      request[14] != null ? request[14].cast<String>() : null;
+      request[13] != null ? request[13].cast<String>() : null;
 
   IncrementalCompilerWrapper compiler = isolateCompilers[isolateId];
 
@@ -599,7 +585,6 @@
       try {
         compiler = new IncrementalCompilerWrapper.forExpressionCompilationOnly(
             component, isolateId, fileSystem, null,
-            suppressWarnings: suppressWarnings,
             enableAsserts: enableAsserts,
             experimentalFlags: experimentalFlags,
             packageConfig: dotPackagesFile);
@@ -761,17 +746,14 @@
   final bool snapshot = request[5];
   final int nullSafety = request[6];
   final List sourceFiles = request[8];
-  final bool suppressWarnings = request[9];
-  final bool enableAsserts = request[10];
+  final bool enableAsserts = request[9];
   final List<String> experimentalFlags =
-      request[11] != null ? request[11].cast<String>() : null;
-  final String packageConfig = request[12];
-  final String multirootFilepaths = request[13];
-  final String multirootScheme = request[14];
-  final String workingDirectory = request[15];
-  // TODO(johnniwinther,bkonyi): Pass verbosity from command line arguments.
-  final String verbosityLevel = Verbosity.defaultValue;
-
+      request[10] != null ? request[10].cast<String>() : null;
+  final String packageConfig = request[11];
+  final String multirootFilepaths = request[12];
+  final String multirootScheme = request[13];
+  final String workingDirectory = request[14];
+  final String verbosityLevel = request[15];
   Uri platformKernelPath = null;
   List<int> platformKernel = null;
   if (request[3] is String) {
@@ -834,7 +816,6 @@
         fileSystem,
         platformKernelPath,
         false,
-        false,
         nullSafety,
         experimentalFlags,
         packagesUri,
@@ -860,7 +841,6 @@
   if (incremental) {
     compiler = await lookupOrBuildNewIncrementalCompiler(
         isolateId, sourceFiles, platformKernelPath, platformKernel,
-        suppressWarnings: suppressWarnings,
         enableAsserts: enableAsserts,
         nullSafety: nullSafety,
         experimentalFlags: experimentalFlags,
@@ -875,7 +855,6 @@
     compiler = new SingleShotCompilerWrapper(
         isolateId, fileSystem, platformKernelPath,
         requireMain: false,
-        suppressWarnings: suppressWarnings,
         enableAsserts: enableAsserts,
         nullSafety: nullSafety,
         experimentalFlags: experimentalFlags,
@@ -1029,13 +1008,13 @@
     kNullSafetyOptionUnspecified /* null safety */,
     1 /* isolateId chosen randomly */,
     [] /* source files */,
-    false /* suppress warnings */,
     false /* enable asserts */,
     null /* experimental_flags */,
     null /* package_config */,
     null /* multirootFilepaths */,
     null /* multirootScheme */,
     null /* original working directory */,
+    'all' /* CFE logging mode */,
   ];
   await _processLoadRequest(request);
 }
diff --git a/runtime/bin/dfe.cc b/runtime/bin/dfe.cc
index 0a6bc48..6935447 100644
--- a/runtime/bin/dfe.cc
+++ b/runtime/bin/dfe.cc
@@ -191,7 +191,7 @@
 
   return Dart_CompileToKernel(sanitized_uri, platform_strong_dill,
                               platform_strong_dill_size, incremental, snapshot,
-                              package_config);
+                              package_config, verbosity());
 }
 
 void DFE::CompileAndReadScript(const char* script_uri,
diff --git a/runtime/bin/dfe.h b/runtime/bin/dfe.h
index 0c38270..b381f9c 100644
--- a/runtime/bin/dfe.h
+++ b/runtime/bin/dfe.h
@@ -42,6 +42,11 @@
   }
   bool use_incremental_compiler() const { return use_incremental_compiler_; }
 
+  void set_verbosity(Dart_KernelCompilationVerbosityLevel verbosity) {
+    verbosity_ = verbosity;
+  }
+  Dart_KernelCompilationVerbosityLevel verbosity() const { return verbosity_; }
+
   // Returns the platform binary file name if the path to
   // kernel binaries was set using SetKernelBinaries.
   const char* GetPlatformBinaryFilename();
@@ -115,6 +120,8 @@
   bool use_dfe_;
   bool use_incremental_compiler_;
   char* frontend_filename_;
+  Dart_KernelCompilationVerbosityLevel verbosity_ =
+      Dart_KernelCompilationVerbosityLevel_All;
 
   // Kernel binary specified on the cmd line.
   uint8_t* application_kernel_buffer_;
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 12e64808..cddacb8 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -1283,6 +1283,7 @@
 #if !defined(DART_PRECOMPILED_RUNTIME)
   // Load vm_platform_strong.dill for dart:* source support.
   dfe.Init();
+  dfe.set_verbosity(Options::verbosity_level());
   if (script_name != nullptr) {
     uint8_t* application_kernel_buffer = NULL;
     intptr_t application_kernel_buffer_size = 0;
diff --git a/runtime/bin/main_options.cc b/runtime/bin/main_options.cc
index d019ce4..517029d 100644
--- a/runtime/bin/main_options.cc
+++ b/runtime/bin/main_options.cc
@@ -34,7 +34,13 @@
     NULL,
 };
 
+// These strings must match the enum VerbosityLevel in main_options.h.
+static const char* kVerbosityLevelNames[] = {
+    "error", "warning", "info", "all", nullptr,
+};
+
 SnapshotKind Options::gen_snapshot_kind_ = kNone;
+VerbosityLevel Options::verbosity_ = kAll;
 bool Options::enable_vm_service_ = false;
 
 #define OPTION_FIELD(variable) Options::variable##_
diff --git a/runtime/bin/main_options.h b/runtime/bin/main_options.h
index 2ab8598..adec23c 100644
--- a/runtime/bin/main_options.h
+++ b/runtime/bin/main_options.h
@@ -63,7 +63,9 @@
 // In main_options.cc there must be a list of strings that matches the enum
 // called k{enum_type}Names. The field is not automatically declared in
 // main_options.cc. It must be explicitly declared.
-#define ENUM_OPTIONS_LIST(V) V(snapshot_kind, SnapshotKind, gen_snapshot_kind)
+#define ENUM_OPTIONS_LIST(V)                                                   \
+  V(snapshot_kind, SnapshotKind, gen_snapshot_kind)                            \
+  V(verbosity, VerbosityLevel, verbosity)
 
 // Callbacks passed to DEFINE_CB_OPTION().
 #define CB_OPTIONS_LIST(V)                                                     \
@@ -79,6 +81,14 @@
   kAppJIT,
 };
 
+// This enum must match the strings in kVerbosityLevelNames in main_options.cc.
+enum VerbosityLevel {
+  kError,
+  kWarning,
+  kInfo,
+  kAll,
+};
+
 static constexpr const char* DEFAULT_VM_SERVICE_SERVER_IP = "localhost";
 static constexpr int DEFAULT_VM_SERVICE_SERVER_PORT = 8181;
 static constexpr int INVALID_VM_SERVICE_SERVER_PORT = -1;
@@ -131,6 +141,9 @@
   static const char* vm_service_server_ip() { return vm_service_server_ip_; }
   static int vm_service_server_port() { return vm_service_server_port_; }
 
+  static Dart_KernelCompilationVerbosityLevel verbosity_level() {
+    return VerbosityLevelToDartAPI(verbosity_);
+  }
 #if !defined(DART_PRECOMPILED_RUNTIME)
   static DFE* dfe() { return dfe_; }
   static void set_dfe(DFE* dfe) { dfe_ = dfe; }
@@ -169,6 +182,22 @@
   static DFE* dfe_;
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
+  static Dart_KernelCompilationVerbosityLevel VerbosityLevelToDartAPI(
+      VerbosityLevel level) {
+    switch (level) {
+      case kError:
+        return Dart_KernelCompilationVerbosityLevel_Error;
+      case kWarning:
+        return Dart_KernelCompilationVerbosityLevel_Warning;
+      case kInfo:
+        return Dart_KernelCompilationVerbosityLevel_Info;
+      case kAll:
+        return Dart_KernelCompilationVerbosityLevel_All;
+      default:
+        UNREACHABLE();
+    }
+  }
+
   // VM Service argument processing.
   static const char* vm_service_server_ip_;
   static bool enable_vm_service_;
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index aae9199..b4415cf 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -3525,6 +3525,13 @@
   intptr_t kernel_size;
 } Dart_KernelCompilationResult;
 
+typedef enum {
+  Dart_KernelCompilationVerbosityLevel_Error = 0,
+  Dart_KernelCompilationVerbosityLevel_Warning,
+  Dart_KernelCompilationVerbosityLevel_Info,
+  Dart_KernelCompilationVerbosityLevel_All,
+} Dart_KernelCompilationVerbosityLevel;
+
 DART_EXPORT bool Dart_IsKernelIsolate(Dart_Isolate isolate);
 DART_EXPORT bool Dart_KernelIsolateIsRunning();
 DART_EXPORT Dart_Port Dart_KernelPort();
@@ -3541,6 +3548,9 @@
  * This is used by the frontend to determine if compilation related information
  * should be printed to console (e.g., null safety mode).
  *
+ * \param verbosity Specifies the logging behavior of the kernel compilation
+ * service.
+ *
  * \return Returns the result of the compilation.
  *
  * On a successful compilation the returned [Dart_KernelCompilationResult] has
@@ -3559,7 +3569,8 @@
                      const intptr_t platform_kernel_size,
                      bool incremental_compile,
                      bool snapshot_compile,
-                     const char* package_config);
+                     const char* package_config,
+                     Dart_KernelCompilationVerbosityLevel verbosity);
 
 typedef struct {
   const char* uri;
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 2f53e5d..1cc6888 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -6095,7 +6095,8 @@
                      intptr_t platform_kernel_size,
                      bool incremental_compile,
                      bool snapshot_compile,
-                     const char* package_config) {
+                     const char* package_config,
+                     Dart_KernelCompilationVerbosityLevel verbosity) {
   API_TIMELINE_DURATION(Thread::Current());
 
   Dart_KernelCompilationResult result = {};
@@ -6105,7 +6106,8 @@
 #else
   result = KernelIsolate::CompileToKernel(
       script_uri, platform_kernel, platform_kernel_size, 0, NULL,
-      incremental_compile, snapshot_compile, package_config);
+      incremental_compile, snapshot_compile, package_config, NULL, NULL,
+      verbosity);
   if (result.status == Dart_KernelCompilationStatus_Ok) {
     Dart_KernelCompilationResult accept_result =
         KernelIsolate::AcceptCompilation();
diff --git a/runtime/vm/kernel_isolate.cc b/runtime/vm/kernel_isolate.cc
index 36bfb1b..168cb76 100644
--- a/runtime/vm/kernel_isolate.cc
+++ b/runtime/vm/kernel_isolate.cc
@@ -31,10 +31,6 @@
 #define Z (T->zone())
 
 DEFINE_FLAG(bool, trace_kernel, false, "Trace Kernel service requests.");
-DEFINE_FLAG(bool,
-            suppress_fe_warnings,
-            false,
-            "Suppress warnings from the FE.");
 DEFINE_FLAG(charp,
             kernel_multiroot_filepaths,
             NULL,
@@ -621,10 +617,6 @@
     num_blob_loads.type = Dart_CObject_kInt64;
     num_blob_loads.value.as_int64 = source->num_blob_loads_;
 
-    Dart_CObject suppress_warnings;
-    suppress_warnings.type = Dart_CObject_kBool;
-    suppress_warnings.value.as_bool = FLAG_suppress_fe_warnings;
-
     Dart_CObject enable_asserts;
     enable_asserts.type = Dart_CObject_kBool;
     enable_asserts.value.as_bool = isolate_group->asserts();
@@ -656,7 +648,6 @@
                                    &is_static_object,
                                    &dills_object,
                                    &num_blob_loads,
-                                   &suppress_warnings,
                                    &enable_asserts,
                                    &experimental_flags_object};
     message.value.as_array.values = message_arr;
@@ -713,7 +704,8 @@
       const char* multiroot_filepaths,
       const char* multiroot_scheme,
       const MallocGrowableArray<char*>* experimental_flags,
-      const char* original_working_directory) {
+      const char* original_working_directory,
+      Dart_KernelCompilationVerbosityLevel verbosity) {
     // Build the message for the Kernel isolate.
     // tag is used to specify which operation the frontend should perform.
     Dart_CObject tag;
@@ -780,10 +772,6 @@
 
     Dart_CObject files = BuildFilesPairs(source_files_count, source_files);
 
-    Dart_CObject suppress_warnings;
-    suppress_warnings.type = Dart_CObject_kBool;
-    suppress_warnings.value.as_bool = FLAG_suppress_fe_warnings;
-
     Dart_CObject enable_asserts;
     enable_asserts.type = Dart_CObject_kBool;
     enable_asserts.value.as_bool = isolate_group != nullptr
@@ -857,6 +845,11 @@
       }
     }
 
+    Dart_CObject verbosity_str;
+    verbosity_str.type = Dart_CObject_kString;
+    verbosity_str.value.as_string =
+        const_cast<char*>(KernelCompilationVerbosityLevelToString(verbosity));
+
     Dart_CObject* message_arr[] = {&tag,
                                    &send_port,
                                    &uri,
@@ -866,13 +859,13 @@
                                    &null_safety,
                                    &isolate_id,
                                    &files,
-                                   &suppress_warnings,
                                    &enable_asserts,
                                    &experimental_flags_object,
                                    &package_config_uri,
                                    &multiroot_filepaths_object,
                                    &multiroot_scheme_object,
-                                   &original_working_directory_object};
+                                   &original_working_directory_object,
+                                   &verbosity_str};
     message.value.as_array.values = message_arr;
     message.value.as_array.length = ARRAY_SIZE(message_arr);
     // Send the message.
@@ -987,6 +980,22 @@
     return NULL;
   }
 
+  static const char* KernelCompilationVerbosityLevelToString(
+      Dart_KernelCompilationVerbosityLevel verbosity) {
+    switch (verbosity) {
+      case Dart_KernelCompilationVerbosityLevel_Error:
+        return "error";
+      case Dart_KernelCompilationVerbosityLevel_Warning:
+        return "warning";
+      case Dart_KernelCompilationVerbosityLevel_Info:
+        return "info";
+      case Dart_KernelCompilationVerbosityLevel_All:
+        return "all";
+      default:
+        UNREACHABLE();
+    }
+  }
+
   // This monitor must be held whenever linked list of requests is accessed.
   static Monitor* requests_monitor_;
 
@@ -1017,7 +1026,8 @@
     bool snapshot_compile,
     const char* package_config,
     const char* multiroot_filepaths,
-    const char* multiroot_scheme) {
+    const char* multiroot_scheme,
+    Dart_KernelCompilationVerbosityLevel verbosity) {
   // Start the kernel Isolate if it is not already running.
   if (!Start()) {
     Dart_KernelCompilationResult result = {};
@@ -1041,7 +1051,8 @@
       kCompileTag, kernel_port, script_uri, platform_kernel,
       platform_kernel_size, source_file_count, source_files,
       incremental_compile, snapshot_compile, package_config,
-      multiroot_filepaths, multiroot_scheme, experimental_flags_, NULL);
+      multiroot_filepaths, multiroot_scheme, experimental_flags_, NULL,
+      verbosity);
 }
 
 bool KernelIsolate::DetectNullSafety(const char* script_uri,
@@ -1060,7 +1071,7 @@
   Dart_KernelCompilationResult result = request.SendAndWaitForResponse(
       kDetectNullabilityTag, kernel_port, script_uri, nullptr, -1, 0, nullptr,
       false, false, package_config, nullptr, nullptr, experimental_flags_,
-      original_working_directory);
+      original_working_directory, Dart_KernelCompilationVerbosityLevel_Error);
   return result.null_safety;
 }
 
@@ -1074,9 +1085,10 @@
   }
 
   KernelCompilationRequest request;
-  return request.SendAndWaitForResponse(kListDependenciesTag, kernel_port, NULL,
-                                        NULL, 0, 0, NULL, false, false, NULL,
-                                        NULL, NULL, experimental_flags_, NULL);
+  return request.SendAndWaitForResponse(
+      kListDependenciesTag, kernel_port, NULL, NULL, 0, 0, NULL, false, false,
+      NULL, NULL, NULL, experimental_flags_, NULL,
+      Dart_KernelCompilationVerbosityLevel_Error);
 }
 
 Dart_KernelCompilationResult KernelIsolate::AcceptCompilation() {
@@ -1091,9 +1103,10 @@
   }
 
   KernelCompilationRequest request;
-  return request.SendAndWaitForResponse(kAcceptTag, kernel_port, NULL, NULL, 0,
-                                        0, NULL, true, false, NULL, NULL, NULL,
-                                        experimental_flags_, NULL);
+  return request.SendAndWaitForResponse(
+      kAcceptTag, kernel_port, NULL, NULL, 0, 0, NULL, true, false, NULL, NULL,
+      NULL, experimental_flags_, NULL,
+      Dart_KernelCompilationVerbosityLevel_Error);
 }
 
 Dart_KernelCompilationResult KernelIsolate::CompileExpressionToKernel(
@@ -1138,7 +1151,8 @@
   KernelCompilationRequest request;
   return request.SendAndWaitForResponse(
       kUpdateSourcesTag, kernel_port, NULL, NULL, 0, source_files_count,
-      source_files, true, false, NULL, NULL, NULL, experimental_flags_, NULL);
+      source_files, true, false, NULL, NULL, NULL, experimental_flags_, NULL,
+      Dart_KernelCompilationVerbosityLevel_Error);
 }
 
 void KernelIsolate::NotifyAboutIsolateShutdown(const Isolate* isolate) {
diff --git a/runtime/vm/kernel_isolate.h b/runtime/vm/kernel_isolate.h
index f312aee..438e883 100644
--- a/runtime/vm/kernel_isolate.h
+++ b/runtime/vm/kernel_isolate.h
@@ -54,7 +54,9 @@
       bool snapshot_compile = false,
       const char* package_config = NULL,
       const char* multiroot_filepaths = NULL,
-      const char* multiroot_scheme = NULL);
+      const char* multiroot_scheme = NULL,
+      Dart_KernelCompilationVerbosityLevel verbosity =
+          Dart_KernelCompilationVerbosityLevel_All);
 
   static bool DetectNullSafety(const char* script_uri,
                                const char* package_config,