如何在Docker桌面扩展中正确显示容器的流输出

tuwxkamq  于 2022-11-22  发布在  Docker
关注(0)|答案(1)|浏览(137)

here所示,使用docker扩展API,您可以流式传输容器的输出,但当我尝试存储每行日志的data.stdout字符串时,它只是不断变化,就像它是一个对象引用一样...我甚至尝试使用data.stdout.slice()复制字符串或使用JSON.stringify(data.stdout)在JSON中转换它,以便获得具有不同引用的新对象,但不起作用:/

...
const[logs,setLogs]=useState<string[]>([]);
...
ddClient.docker.cli.exec('logs', ['-f', data.Id], {
    stream: {
      onOutput(data): void {
        console.log(data.stdout);
        setLogs([...logs, data.stdout]);
      },
      onError(error: unknown): void {
        ddClient.desktopUI.toast.error('An error occurred');
        console.log(error);
      },
      onClose(exitCode) {
        console.log("onClose with exit code " + exitCode);
      },
      splitOutputLines: true,
    },
  });
qxgroojn

qxgroojn1#

Docker扩展团队成员。我不是ReactMaven,所以我的解释可能是错误的,但我认为这个问题与React如何工作有关。
在你的组件中,调用ddClient.docker.cli.exec('logs', ['-f'], ...)会在每次从后端流来一些数据时更新logs状态的值。这个更新会使组件重新呈现并再次执行所有的东西。因此,你会有很多对ddClient.docker.cli.exec的调用被执行。而且它会呈指数级增长。
问题在于,由于存在许多ddClient.docker.cli.exec调用,因此也存在同样多的对setLogs的调用同时更新logs的状态,但是扩展logs的值并不能保证该值是最后一次设置的。
您可以尝试以下方法来移除Docker Extensions SDK。它做的是完全相同的事情:它每400ms更新setTimeout回调内的content状态。由于setTimeout在每次渲染时运行并且从不清除,因此将同时存在content的许多更新。

let counter = 0;

export function App() {

  const [content, setContent] = React.useState<string[]>([]);

  setTimeout(() => {
    counter++;
    setContent([...content, "\n " + counter]);
  }, 400);

  return (<div>{content}</div>);
}

你会看到奇怪的结果:)
以下是如何执行您要执行的操作:

const ddClient = createDockerDesktopClient();

export function App() {

  const [logs, setLogs] = React.useState<string[]>([]);

  useEffect(() => {
    const listener = ddClient.docker.cli.exec('logs', ['-f', "xxxx"], {
      stream: {
        onOutput(data): void {
          console.log(data.stdout);
          setLogs((current) => [...current, data.stdout]);
        },
        onError(error: unknown): void {
          ddClient.desktopUI.toast.error('An error occurred');
          console.log(error);
        },
        onClose(exitCode) {
          console.log("onClose with exit code " + exitCode);
        },
        splitOutputLines: true,
      },
    });

    return () => {
      listener.close();
    }
  }, []);

  return (
    <>
      <h1>Logs</h1>
      <div>{logs}</div>
    </>
  );
}

这里发生的是

  • ddClient.docker.cli.exec的调用是在useEffect中完成的
  • 该效果返回一个关闭连接的函数,以便在卸载组件时关闭与派生命令的连接
  • 该效果将空数组作为第二个参数,以便仅在挂载组件时调用它(因此不是在每次重新渲染时)
  • 不是阅读logs,而是向setLogs函数提供回调,以确保将包含在data.stdout中的最新值添加到状态的最新版本中,

要尝试使用该命令,请确保更新了logs命令的参数数组。

相关问题