Kaynağa Gözat

(enh) unify the log output in docker build process (#3961)

Signed-off-by: niliy <WannaTen@users.noreply.github.com>
niliy01 1 yıl önce
ebeveyn
işleme
0f6fb0f80e
1 değiştirilmiş dosya ile 50 ekleme ve 35 silme
  1. 50 35
      openhands/runtime/builder/docker.py

+ 50 - 35
openhands/runtime/builder/docker.py

@@ -26,11 +26,16 @@ class DockerRuntimeBuilder(RuntimeBuilder):
             logger.error(f'Sandbox image build failed: {e}')
             logger.error(f'Sandbox image build failed: {e}')
             raise RuntimeError(f'Sandbox image build failed: {e}')
             raise RuntimeError(f'Sandbox image build failed: {e}')
 
 
+        layers: dict[str, dict[str, str]] = {}
+        previous_layer_count = 0
         for log in build_logs:
         for log in build_logs:
             if 'stream' in log:
             if 'stream' in log:
                 logger.info(log['stream'].strip())
                 logger.info(log['stream'].strip())
             elif 'error' in log:
             elif 'error' in log:
                 logger.error(log['error'].strip())
                 logger.error(log['error'].strip())
+            elif 'status' in log:
+                self._output_build_progress(log, layers, previous_layer_count)
+                previous_layer_count = len(layers)
             else:
             else:
                 logger.info(str(log))
                 logger.info(str(log))
 
 
@@ -85,39 +90,13 @@ class DockerRuntimeBuilder(RuntimeBuilder):
                     'Image not found locally. Trying to pull it, please wait...'
                     'Image not found locally. Trying to pull it, please wait...'
                 )
                 )
 
 
-                layers = {}
+                layers: dict[str, dict[str, str]] = {}
                 previous_layer_count = 0
                 previous_layer_count = 0
                 for line in self.docker_client.api.pull(
                 for line in self.docker_client.api.pull(
                     image_name, stream=True, decode=True
                     image_name, stream=True, decode=True
                 ):
                 ):
-                    if 'id' in line and 'progressDetail' in line:
-                        layer_id = line['id']
-                        if layer_id not in layers:
-                            layers[layer_id] = {'last_logged': 0}
-
-                        if (
-                            'total' in line['progressDetail']
-                            and 'current' in line['progressDetail']
-                        ):
-                            total = line['progressDetail']['total']
-                            current = line['progressDetail']['current']
-                            percentage = (current / total) * 100
-
-                            # refresh process bar in console if stdout is a tty
-                            if sys.stdout.isatty():
-                                layers[layer_id]['last_logged'] = percentage
-                                self._output_pull_progress(layers, previous_layer_count)
-                                previous_layer_count = len(layers)
-                            # otherwise Log only if percentage is at least 10% higher than last logged
-                            elif percentage - layers[layer_id]['last_logged'] >= 10:
-                                logger.info(
-                                    f'Layer {layer_id}: {percentage:.0f}% downloaded'
-                                )
-                                layers[layer_id]['last_logged'] = percentage
-
-                    elif 'status' in line:
-                        logger.info(line['status'])
-
+                    self._output_build_progress(line, layers, previous_layer_count)
+                    previous_layer_count = len(layers)
                 logger.info('Image pulled')
                 logger.info('Image pulled')
                 return True
                 return True
             except docker.errors.ImageNotFound:
             except docker.errors.ImageNotFound:
@@ -133,9 +112,45 @@ class DockerRuntimeBuilder(RuntimeBuilder):
                 logger.warning(msg)
                 logger.warning(msg)
                 return False
                 return False
 
 
-    def _output_pull_progress(self, layers: dict, previous_layer_count: int) -> None:
-        sys.stdout.write('\033[F' * previous_layer_count)
-        for lid, layer_data in sorted(layers.items()):
-            sys.stdout.write('\033[K')
-            print(f'Layer {lid}: {layer_data["last_logged"]:.0f}% downloaded')
-        sys.stdout.flush()
+    def _output_build_progress(
+        self, current_line: dict, layers: dict, previous_layer_count: int
+    ) -> None:
+        if 'id' in current_line and 'progressDetail' in current_line:
+            layer_id = current_line['id']
+            if layer_id not in layers:
+                layers[layer_id] = {'status': '', 'progress': '', 'last_logged': 0}
+
+            if 'status' in current_line:
+                layers[layer_id]['status'] = current_line['status']
+
+            if 'progress' in current_line:
+                layers[layer_id]['progress'] = current_line['progress']
+
+            if (
+                'total' in current_line['progressDetail']
+                and 'current' in current_line['progressDetail']
+            ):
+                total = current_line['progressDetail']['total']
+                current = current_line['progressDetail']['current']
+                percentage = (current / total) * 100
+            else:
+                percentage = 0
+
+            # refresh process bar in console if stdout is a tty
+            if sys.stdout.isatty():
+                sys.stdout.write('\033[F' * previous_layer_count)
+                for lid, layer_data in sorted(layers.items()):
+                    sys.stdout.write('\033[K')
+                    print(
+                        f'Layer {lid}: {layer_data["progress"]} {layer_data["status"]}'
+                    )
+                sys.stdout.flush()
+            # otherwise Log only if percentage is at least 10% higher than last logged
+            elif percentage != 0 and percentage - layers[layer_id]['last_logged'] >= 10:
+                logger.info(
+                    f'Layer {layer_id}: {layers[layer_id]["progress"]} {layers[layer_id]["status"]}'
+                )
+
+            layers[layer_id]['last_logged'] = percentage
+        elif 'status' in current_line:
+            logger.info(current_line['status'])