The Python Oracle

How to stream the logs in docker python API?

--------------------------------------------------
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Magic Ocean Looping

--

Chapters
00:00 How To Stream The Logs In Docker Python Api?
00:37 Answer 1 Score 8
01:02 Accepted Answer Score 7
01:20 Answer 3 Score 6
01:59 Answer 4 Score 2
02:42 Answer 5 Score 1
02:57 Thank you

--

Full question
https://stackoverflow.com/questions/4354...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #docker

#avk47



ACCEPTED ANSWER

Score 8


Streaming the docker build logs can be done using the low-level APIs given in docker-py as follows,

        here = os.path.dirname(__file__)
        dockerfile = os.path.join(here, 'app', 'nextdir')
        docker_client = docker.APIClient(base_url='unix://var/run/docker.sock')
        generator = docker_client.build(path=dockerfile, tag='app:v.2.4', rm=True)
        while True:
            try:
                output = generator.__next__
                output = output.strip('\r\n')
                json_output = json.loads(output)
                if 'stream' in json_output:
                    click.echo(json_output['stream'].strip('\n'))
            except StopIteration:
                click.echo("Docker image build complete.")
                break
            except ValueError:
                click.echo("Error parsing output from docker image build: %s" % output)



ANSWER 2

Score 8


According to the docs, the image build now returns a tuple with both the image and the build logs

The first item is the Image object for the image that was build. The second item is a generator of the build logs as JSON-decoded objects.

And modifying @havock solution accordingly:

import docker

client = docker.from_env()
image, build_logs = client.images.build(**your_build_kwargs)

for chunk in build_logs:
    if 'stream' in chunk:
        for line in chunk['stream'].splitlines():
            log.debug(line)



ANSWER 3

Score 6


You may use the low-level API client. The build() function will return a generator that you can iterate to grab chunks of the build log.

The generator will yield a string containing a JSON object, you may call json.loads() on it or you can use the decode=True parameter in the build() function that will do that for you.

Once you grab the 'stream' key from the yielded dictionary you may just print() it, but if you need to send it to a logger it may be better to do it line by line, as the chunk received will contain more than one line.

One option of such code is as follows:

from docker import APIClient

client = APIClient(base_url='unix://var/run/docker.sock')

# Build docker image
log.info('Building docker image ...')
streamer = client.build(
    decode=True,
    path=args.path,
    tag=args.tag,
)

for chunk in streamer:
    if 'stream' in chunk:
        for line in chunk['stream'].splitlines():
            log.debug(line)



ANSWER 4

Score 2


Docker low level build has the ability to directly decode the output to a dictionary. For that use decode=True.

I used mashumaro to convert the dictionary to a dataclass. This is useful if you like type hints. To use dataclasses you need at least python3.7.

Install mashumaro:

pip install mashumaro

The dataclass:

@dataclass
class DockerStreamOutput(DataClassDictMixin):
    stream: str = None
    aux: str = None

Build your image:

from mashumaro import DataClassDictMixin, MissingField
generator = client.api.build(
            path=container_path,
            tag=tag_name,
            dockerfile=dockerfile_path,
            decode=True  # encode to dict
        )

for line in generator:
    try:
        stream_output: DockerStreamOutput = DockerStreamOutput.from_dict(line)
        stream: str = stream_output.stream
        if stream:
            logging.info(stream.strip())
    except MissingField:
        logging.error(line)

Hope this helps.