Conversation
| cmd = exec.Command("docker", "network", "connect", stackNetwork, serviceContainer) | ||
| if err := cmd.Run(); err != nil { | ||
| return nil, errors.Wrap(err, "could not attach service container to stack network") | ||
| } |
There was a problem hiding this comment.
I think we still need to attach the service container to the stack network for metrics data streams to work, no?
There was a problem hiding this comment.
I forgot about this requirement. I will bring it back.
| if err != nil { | ||
| return nil, errors.Wrap(err, "could not create STDOUT file") | ||
| } | ||
| service.stdout = outFile |
There was a problem hiding this comment.
This is how a Docker-based service's STDOUT stream was being written to a log file on the local filesystem. How are we capturing a Docker-based service's logs now?
Related: what would be the syntax in a package's test configuration file to refer to such logs? In the current implementation the syntax is {{ STDOUT }} and {{ STDERR }}.
There was a problem hiding this comment.
I considered this as a base assumption for this change - to base only on log file resources, as most apps emit them as two log streams (application, access). I think it simplified the implementation as we don't have to deal with opening and closing file.
In case of stdout, stderr we can "tee" these streams to local files.
I don't insist on such design, just wanted to handle all streams the same way (via filesystem).
There was a problem hiding this comment.
Okay, let me try to understand this with the apache Docker container. If you look at elastic/integrations#263, the system test configuration file for the apache/access log dataset (for the current implementation of the system test runner) looks like this:
How do you see this changing in the new implementation (this PR)?
There was a problem hiding this comment.
We know in advance that service logs are available in the directory /tmp/service_logs/ in the agent container.
I suppose the variable var.paths can contain /tmp/service_logs/access.log*?
EDIT:
Hmm.. ok, I see your point. We should introduce env variables there to be consistent. WDYT?
EDIT2:
We have LogsFolderLocal which is set to /tmp/service_logs. I think in the end it would be - {{ LogsFolderLocal }}/access.log*
EDIT3:
I triple-checked it. You're right, it's not value we want here :) I will adjust the PR.
There was a problem hiding this comment.
Fixed. Additional context properties are exposed: LogsFolderLocal and LogsFolderAgent.
Speaking about apache, it requires following lines to be present in httpd.conf:
ErrorLog logs/error_log
CustomLog "logs/access_log" combined
There was a problem hiding this comment.
Thanks, so my understanding is that the system test configuration file for the apache/access log dataset would look like:
vars: ~
dataset:
vars:
paths:
- "{{LogsFolderAgent}}/access.log*"
And httpd.conf would be configured as you showed in your last comment above.
But why would a package author just know that logs/access_log from their httpd.conf should be referred to as {{LogsFolderAgent}}/access_log*? I'm guessing this comes from the volume mount definitions that they would define in the docker-compose file for their service? Perhaps this last piece would be clear to me if you can make a PR to elastic/integrations#263 showing the necessary changes.
There was a problem hiding this comment.
Thanks, so my understanding is that the system test configuration file for the apache/access log dataset would look like:
Correct.
And httpd.conf would be configured as you showed in your last comment above.
Yes
But why would a package author just know that
logs/access_logfrom theirhttpd.confshould be referred to as{{LogsFolderAgent}}/access_log*?
Frankly speaking I considered this as part of standard stack setup - the Elastic Agent has a directory bound to service logs of the service under tests (SUT). As the agent is a long running instance and it's booted up first, it needs to create the volume (no the SUT). The local directory with logs can customized on the SUT side:
version: '2.3'
services:
apache:
image: docker.elastic.co/integrations-ci/beats-apache:${SERVICE_VERSION:-2.4.20}-1
ports:
- 80
volumes:
- ${ELASTIC_PACKAGE_SERVICE_LOGS_DIR}:/usr/local/apache2/logs
To be honest I had in mind to document both {{LogsFolderAgent}} and ${ELASTIC_PACKAGE_SERVICE_LOGS_DIR} in some README or guide.
I'm willing to adjust it if you have an idea on how we can simplify it.
There was a problem hiding this comment.
Okay, I understand the complete picture now. Thanks.
It's a bit annoying that these two variables slightly betray the inner workings of how logs get from a service container to the agent container. It would be nice if a user didn't need to know about that implementation detail.
What if we make both variables (from a user's perspective) the same and something more generic, e.g. SERVICE_LOGS_DIR? Then, as a user, it is more intuitive that I'm mapping my service logs folder (/usr/local/apache2/logs) to ${SERVICE_LOGS_DIR} in my Docker Compose file and then reading from the same* folder (- "{{SERVICE_LOGS_DIR}}/access.log*") in my system test config file.
I realize it breaks naming conventions as we're mixing env var naming conventions (snake case) with Go struct field naming conventions (camel case). But IMHO that's a worthy sacrifice for a better UX. Or we could even leave the struct field as camel case but in the context application function, we could first convert all snake case template identifiers in the config file to camel case on the fly, right before applying the context to it.
*Internally we know, of course, that it's not the same folder.
There was a problem hiding this comment.
Good call, it's definitely a better user experience.
|
|
||
| // Connect service network with stack network (for the purpose of metrics collection) | ||
| stackNetwork := fmt.Sprintf("%s_default", stack.DockerComposeProjectName) | ||
| logger.Debugf("attaching service container %s to stack network %s", serviceContainer, stackNetwork) |
There was a problem hiding this comment.
Maybe bring back the debug logs (here and in other useful places) so we can tell what's going on while troubleshooting?
| // the service are stored on the Agent container's filesystem. | ||
| Agent string | ||
| } | ||
| } |
There was a problem hiding this comment.
Any particular reason not to keep the same hierarchical structure as before? Just curious if the hierarchy vs. flat is a personal preference or if there's a stronger reason you prefer flat?
There was a problem hiding this comment.
I kept it flat, because we've only two configuration options. I adjusted it back so it's again structured.
| return data, errors.Wrap(err, "could not render data with context") | ||
| return data, errors.Wrap(err, "parsing template body failed") | ||
| } | ||
| tmpl.RegisterHelpers(ctxt.Aliases()) |
ycombinator
left a comment
There was a problem hiding this comment.
LGTM. Very nice — much better than my stream redirection hack 😄 👍 🎉
Closes: #85
I'm opening as draft, because we need to have a service that writes logs to files.
I introduced also service logs direcotyr env:
ELASTIC_PACKAGE_SERVICE_LOGS_DIR