2018-12-14 06:44:47 +03:00
|
|
|
#!/usr/bin/env python3
|
2019-06-20 02:58:25 +03:00
|
|
|
# Copyright (c) Facebook, Inc. and its affiliates.
|
2018-12-14 06:44:47 +03:00
|
|
|
#
|
2019-06-20 02:58:25 +03:00
|
|
|
# This software may be used and distributed according to the terms of the
|
|
|
|
# GNU General Public License version 2.
|
2018-12-14 06:44:47 +03:00
|
|
|
|
|
|
|
import pathlib
|
|
|
|
|
|
|
|
from .lib.service_test_case import (
|
|
|
|
ManagedFakeEdenFSMixin,
|
|
|
|
ServiceTestCaseBase,
|
|
|
|
service_test,
|
|
|
|
)
|
|
|
|
from .start_test import run_eden_start_with_real_daemon
|
|
|
|
|
|
|
|
|
|
|
|
class ServiceLogTestBase(ServiceTestCaseBase):
|
2020-10-15 06:19:13 +03:00
|
|
|
"""Test how the EdenFS service stores its logs."""
|
2018-12-14 06:44:47 +03:00
|
|
|
|
|
|
|
def setUp(self) -> None:
|
|
|
|
super().setUp()
|
2020-04-23 00:59:26 +03:00
|
|
|
self.eden_dir = self.make_temp_dir("eden")
|
2018-12-14 06:44:47 +03:00
|
|
|
|
|
|
|
@property
|
|
|
|
def log_file_path(self) -> pathlib.Path:
|
|
|
|
return self.eden_dir / "logs" / "edenfs.log"
|
|
|
|
|
|
|
|
|
Make systemd service log to file
Summary:
When run inside the systemd service (fb-edenfs@.service), edenfs' logs are written to `/var/log/messages` (on Facebook dev servers). This is undesirable, since those logs have a bunch of noise.
Make systemd-managed edenfs log to `~/local/.eden/logs/edenfs.log` instead, matching the behavior of custom-managed edenfs.
---
I considered using systemd's StandardOutput= and StandardError= directives [1], but they have limitations:
* **StandardOutput=file:%f/logs/edenfs.log**: When the `logs` directory is missing, systemd does not create it. In this case, systemd fails when it opens the log file, so systemd refuses to start the service.
* **StandardOutput=journal** [2]: journald and journalctl are broken for user services. Logging to journald only works with persistent journal storage [3][4], but Facebook uses volatile journal storage.
* **StandardOutput=syslog** [5]: rsyslog seems designed for system administrators, not users. I didn't investigate much, but I suspect it's impossible to make rsyslog write to a user-controlled path such as `~/local/.eden/logs/edenfs.log`.
* **LogsDirectory=%f/logs and StandardOutput=file:%L/edenfs.log** [6][7]: LogsDirectory= does exactly what we need, except it only supports paths relative to `/var/log` or `~/.config/log/`. `LogsDirectory=%f/logs` does not work, and systemd will ignore such a directive.
* **StandardOutput=file:%f/logs/edenfs.log and a `mkdir` service**: If we create a service which just creates the `logs` directory, and make fb-edenfs@.service depend upon that service, systemd can successfully open the log file [8]. In theory, using StandardOutput= would cause errors like "could not set resource limits" to be logged to `edenfs.log`. In practice, systemd does not respect the service's logging configuration when reporting such errors [9]. Therefore, this solution is no better than the manual redirect.
[1] https://www.freedesktop.org/software/systemd/man/systemd.exec.html#StandardOutput=
[2] https://www.freedesktop.org/software/systemd/man/systemd-journald.service.html#
[3] https://www.freedesktop.org/software/systemd/man/journald.conf.html#SplitMode=
[4] https://lists.freedesktop.org/archives/systemd-devel/2016-October/037554.html
[5] https://www.rsyslog.com/
[6] https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RuntimeDirectory=
[7] https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers
[8]
```name=fb-edenfs-logs@.service
[Service]
Environment=EDENFS_CONFIG_DIR=%f
ExecStart=/bin/sh -c ' \
set -e; \
set -u; \
\
/bin/mkdir -p -- "$${EDENFS_CONFIG_DIR}/logs""; \
'
```
```name=fb-edenfs@.service
[Unit]
After=fb-edenfs-logs@%i.service
Requires=fb-edenfs-logs@%i.service
```
[9] https://github.com/systemd/systemd/blob/fd0ec39d3848029abd3a439e84c5728331de2128/src/basic/log.c#L560-L639
Reviewed By: simpkins
Differential Revision: D13422459
fbshipit-source-id: 57c575a6f377812caa2a79168778576c6ccff33e
2018-12-18 02:08:05 +03:00
|
|
|
@service_test
|
2018-12-14 06:44:47 +03:00
|
|
|
class ServiceLogFakeEdenFSTest(ServiceLogTestBase):
|
|
|
|
def test_fake_edenfs_writes_logs_to_file_in_eden_dir(self) -> None:
|
|
|
|
self.assertFalse(
|
|
|
|
self.log_file_path.exists(),
|
|
|
|
f"{self.log_file_path} should not exist before starting fake_edenfs",
|
|
|
|
)
|
|
|
|
with self.spawn_fake_edenfs(self.eden_dir):
|
|
|
|
self.assertTrue(
|
|
|
|
self.log_file_path.exists(),
|
|
|
|
f"fake_edenfs should create {self.log_file_path}",
|
|
|
|
)
|
|
|
|
self.assertIn("Starting fake edenfs daemon", self.log_file_path.read_text())
|
|
|
|
|
Make systemd service log to file
Summary:
When run inside the systemd service (fb-edenfs@.service), edenfs' logs are written to `/var/log/messages` (on Facebook dev servers). This is undesirable, since those logs have a bunch of noise.
Make systemd-managed edenfs log to `~/local/.eden/logs/edenfs.log` instead, matching the behavior of custom-managed edenfs.
---
I considered using systemd's StandardOutput= and StandardError= directives [1], but they have limitations:
* **StandardOutput=file:%f/logs/edenfs.log**: When the `logs` directory is missing, systemd does not create it. In this case, systemd fails when it opens the log file, so systemd refuses to start the service.
* **StandardOutput=journal** [2]: journald and journalctl are broken for user services. Logging to journald only works with persistent journal storage [3][4], but Facebook uses volatile journal storage.
* **StandardOutput=syslog** [5]: rsyslog seems designed for system administrators, not users. I didn't investigate much, but I suspect it's impossible to make rsyslog write to a user-controlled path such as `~/local/.eden/logs/edenfs.log`.
* **LogsDirectory=%f/logs and StandardOutput=file:%L/edenfs.log** [6][7]: LogsDirectory= does exactly what we need, except it only supports paths relative to `/var/log` or `~/.config/log/`. `LogsDirectory=%f/logs` does not work, and systemd will ignore such a directive.
* **StandardOutput=file:%f/logs/edenfs.log and a `mkdir` service**: If we create a service which just creates the `logs` directory, and make fb-edenfs@.service depend upon that service, systemd can successfully open the log file [8]. In theory, using StandardOutput= would cause errors like "could not set resource limits" to be logged to `edenfs.log`. In practice, systemd does not respect the service's logging configuration when reporting such errors [9]. Therefore, this solution is no better than the manual redirect.
[1] https://www.freedesktop.org/software/systemd/man/systemd.exec.html#StandardOutput=
[2] https://www.freedesktop.org/software/systemd/man/systemd-journald.service.html#
[3] https://www.freedesktop.org/software/systemd/man/journald.conf.html#SplitMode=
[4] https://lists.freedesktop.org/archives/systemd-devel/2016-October/037554.html
[5] https://www.rsyslog.com/
[6] https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RuntimeDirectory=
[7] https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers
[8]
```name=fb-edenfs-logs@.service
[Service]
Environment=EDENFS_CONFIG_DIR=%f
ExecStart=/bin/sh -c ' \
set -e; \
set -u; \
\
/bin/mkdir -p -- "$${EDENFS_CONFIG_DIR}/logs""; \
'
```
```name=fb-edenfs@.service
[Unit]
After=fb-edenfs-logs@%i.service
Requires=fb-edenfs-logs@%i.service
```
[9] https://github.com/systemd/systemd/blob/fd0ec39d3848029abd3a439e84c5728331de2128/src/basic/log.c#L560-L639
Reviewed By: simpkins
Differential Revision: D13422459
fbshipit-source-id: 57c575a6f377812caa2a79168778576c6ccff33e
2018-12-18 02:08:05 +03:00
|
|
|
def test_fake_edenfs_appends_to_existing_log_file(self) -> None:
|
2019-03-04 23:56:05 +03:00
|
|
|
self.log_file_path.parent.mkdir(exist_ok=True, parents=True)
|
Make systemd service log to file
Summary:
When run inside the systemd service (fb-edenfs@.service), edenfs' logs are written to `/var/log/messages` (on Facebook dev servers). This is undesirable, since those logs have a bunch of noise.
Make systemd-managed edenfs log to `~/local/.eden/logs/edenfs.log` instead, matching the behavior of custom-managed edenfs.
---
I considered using systemd's StandardOutput= and StandardError= directives [1], but they have limitations:
* **StandardOutput=file:%f/logs/edenfs.log**: When the `logs` directory is missing, systemd does not create it. In this case, systemd fails when it opens the log file, so systemd refuses to start the service.
* **StandardOutput=journal** [2]: journald and journalctl are broken for user services. Logging to journald only works with persistent journal storage [3][4], but Facebook uses volatile journal storage.
* **StandardOutput=syslog** [5]: rsyslog seems designed for system administrators, not users. I didn't investigate much, but I suspect it's impossible to make rsyslog write to a user-controlled path such as `~/local/.eden/logs/edenfs.log`.
* **LogsDirectory=%f/logs and StandardOutput=file:%L/edenfs.log** [6][7]: LogsDirectory= does exactly what we need, except it only supports paths relative to `/var/log` or `~/.config/log/`. `LogsDirectory=%f/logs` does not work, and systemd will ignore such a directive.
* **StandardOutput=file:%f/logs/edenfs.log and a `mkdir` service**: If we create a service which just creates the `logs` directory, and make fb-edenfs@.service depend upon that service, systemd can successfully open the log file [8]. In theory, using StandardOutput= would cause errors like "could not set resource limits" to be logged to `edenfs.log`. In practice, systemd does not respect the service's logging configuration when reporting such errors [9]. Therefore, this solution is no better than the manual redirect.
[1] https://www.freedesktop.org/software/systemd/man/systemd.exec.html#StandardOutput=
[2] https://www.freedesktop.org/software/systemd/man/systemd-journald.service.html#
[3] https://www.freedesktop.org/software/systemd/man/journald.conf.html#SplitMode=
[4] https://lists.freedesktop.org/archives/systemd-devel/2016-October/037554.html
[5] https://www.rsyslog.com/
[6] https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RuntimeDirectory=
[7] https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers
[8]
```name=fb-edenfs-logs@.service
[Service]
Environment=EDENFS_CONFIG_DIR=%f
ExecStart=/bin/sh -c ' \
set -e; \
set -u; \
\
/bin/mkdir -p -- "$${EDENFS_CONFIG_DIR}/logs""; \
'
```
```name=fb-edenfs@.service
[Unit]
After=fb-edenfs-logs@%i.service
Requires=fb-edenfs-logs@%i.service
```
[9] https://github.com/systemd/systemd/blob/fd0ec39d3848029abd3a439e84c5728331de2128/src/basic/log.c#L560-L639
Reviewed By: simpkins
Differential Revision: D13422459
fbshipit-source-id: 57c575a6f377812caa2a79168778576c6ccff33e
2018-12-18 02:08:05 +03:00
|
|
|
self.log_file_path.write_text("test log messages\n")
|
|
|
|
with self.spawn_fake_edenfs(self.eden_dir):
|
|
|
|
pass
|
|
|
|
self.assertIn("test log messages", self.log_file_path.read_text())
|
|
|
|
|
2018-12-14 06:44:47 +03:00
|
|
|
|
|
|
|
class ServiceLogRealEdenFSTest(ManagedFakeEdenFSMixin, ServiceLogTestBase):
|
|
|
|
def test_real_edenfs_writes_logs_to_file_in_eden_dir(self) -> None:
|
|
|
|
self.assertFalse(
|
|
|
|
self.log_file_path.exists(),
|
|
|
|
f"{self.log_file_path} should not exist before starting edenfs",
|
|
|
|
)
|
2020-04-23 00:59:26 +03:00
|
|
|
self.exit_stack.enter_context(
|
|
|
|
run_eden_start_with_real_daemon(
|
|
|
|
eden_dir=self.eden_dir,
|
|
|
|
etc_eden_dir=self.etc_eden_dir,
|
|
|
|
home_dir=self.home_dir,
|
|
|
|
systemd=False,
|
2018-12-14 06:44:47 +03:00
|
|
|
)
|
2020-04-23 00:59:26 +03:00
|
|
|
)
|
|
|
|
self.assertTrue(
|
|
|
|
self.log_file_path.exists(), f"edenfs should create {self.log_file_path}"
|
|
|
|
)
|
|
|
|
self.assertIn("Starting edenfs", self.log_file_path.read_text())
|