Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix logging in CLI #11472

Merged
merged 8 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -3683,6 +3683,7 @@ lazy val `engine-runner` = project
.dependsOn(cli)
.dependsOn(`profiling-utils`)
.dependsOn(`library-manager`)
.dependsOn(`distribution-manager`)
.dependsOn(`edition-updater`)
.dependsOn(`runtime-parser`)
.dependsOn(`logging-service`)
Expand Down
58 changes: 39 additions & 19 deletions docs/infrastructure/logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,17 @@ involving the centralized logging service.

## Configuration

The logging settings should be placed under the `logging-service` key of the
`application.conf` config. Each of the main components can customize format and
output target via section in `application.conf` configuration file. The
All logging settings are configured via the `logging-service` section of the
`application.conf` config file. Each of the main components can customize format
and output target via section in `application.conf` configuration file. The
configuration is using HOCON-style, as defined by
[lightbend/config](https://github.com/lightbend/config). Individual values
accepted in the config are inspired by SLF4J's properties, formatting and
implementations.
implementations. Currently 3 components define logging configuration:

- [`project-manager`](../../lib/scala/project-manager/src/main/resources/application.conf)
- [`launcher`](../../engine/launcher/src/main/resources/application.conf)
- [CLI](../../engine/runner/src/main/resources/application.conf)

The configuration has two main sections:

Expand All @@ -57,8 +61,8 @@ representation is available as an instance of
programmatically initialize loggers.

As per [configuration schema](https://github.com/lightbend/config) any key can
have a default value that can be overridden by an environment variable. For
example
be defined with a default value that can be overridden by an environment
variable. For example

```
{
Expand All @@ -72,10 +76,18 @@ it is defined during loading of the config file.

### Custom Log Levels

The `logging-service.logger` configuration provides an ability to override the
default application log level for particular loggers. In the `logger` subconfig
the key specifies the logger name (or it's prefix) and the value specifies the
log level for that logger.
Possible log level values are (in the order of precedence):

- `error`
- `warn`
- `info`
- `debug`
- `trace`

The `logging-service.logger` configuration section provides an ability to
override the default application log level for particular loggers. In the
`logger` subconfig the key specifies the logger name (or it's prefix) and the
value specifies the log level for that logger.

```
logging-service.logger {
Expand Down Expand Up @@ -117,7 +129,7 @@ properties always have a higher priority over those defined in the

### Appenders

Log output target is also configured in the `application.conf` files in the
Log output target is configured in the `application.conf` files in the
"appenders" section ("appender" is equivalent to `java.util.logging.Handler`
semantics). Each appender section can provide further required and optional
key/value pairs, to better customize the log target output.
Expand All @@ -133,8 +145,10 @@ Currently supported are
a sentry.io service

The appenders are defined by the `logging-service.appenders`. Currently only a
single appender can be selected at a time. The selection may also be done via an
environmental variable but it depends on which component we are executing.
single appender can be selected at a time, although additional
[logging to file](#logging-to-file) is supported. The selection may also be done
via an environmental variable but it depends on which component we are
executing.

- `project-manager` - project manager by default starts a centralized logging
server that collects logs (as defined in `logging-service.server` config key)
Expand Down Expand Up @@ -352,18 +366,24 @@ way it can verify that all logs are being reported within the provided code.
### Logging to file

By default Enso will attempt to persist (verbose) logs into a designated log
file. This means that even though a user might be shown `WARNING` level logs in
the console, logs with up to `DEBUG` level will be dumped into the log file. A
user can disable this parallel logging to a file by setting the environment
variable:
file. This means that even though a user might be shown only `WARNING` level
logs in the console, logs with up to `DEBUG` or `TRACE` level, including full
stacktraces, can be dumped into the log file. A user can disable this parallel
logging to a file by setting the environment variable:

```
ENSO_LOG_TO_FILE=false project-manager ...
```

Users can also modify the default maximal log level, `DEBUG`, used when logging
to a log file by setting the environment variable:
Users can fully control the maximal log level used when logging to a log file by
setting the environment variable:

```
ENSO_LOG_TO_FILE_LOG_LEVEL=trace project-manager ...
```

For example, in the above example `project-manager` will log events of up-to
`trace` in the log file.

**Note** Logging to a file requires presence of the `file`
[appender](#file-appender) in the `logging-service.appenders` section.
10 changes: 6 additions & 4 deletions engine/runner/src/main/java/org/enso/runner/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ public class Main {
private static final String WARNINGS_LIMIT = "warnings-limit";
private static final String SYSTEM_PROPERTY = "vm.D";

private static final String DEFAULT_MAIN_METHOD_NAME = "main";

private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Main.class);

Main() {}
Expand Down Expand Up @@ -854,20 +856,20 @@ private void runPackage(
java.util.List<String> additionalArgs) {
var topScope = context.getTopScope();
var mainModule = topScope.getModule(mainModuleName);
runMain(mainModule, projectPath, additionalArgs, "main");
runMain(mainModule, projectPath, additionalArgs, DEFAULT_MAIN_METHOD_NAME);
}

private void runSingleFile(
PolyglotContext context, File file, java.util.List<String> additionalArgs) {
var mainModule = context.evalModule(file);
runMain(mainModule, file, additionalArgs, "main");
runMain(mainModule, file, additionalArgs, DEFAULT_MAIN_METHOD_NAME);
}

private void runMain(
Module mainModule,
File rootPkgPath,
java.util.List<String> additionalArgs,
String mainMethodName // = "main"
String mainMethodName // = DEFAULT_MAIN_METHOD_NAME
) {
try {
var mainType = mainModule.getAssociatedType();
Expand All @@ -881,7 +883,7 @@ private void runMain(
throw exitFail();
}
var main = mainFun.get();
if (!"main".equals(mainMethodName)) {
if (!DEFAULT_MAIN_METHOD_NAME.equals(mainMethodName)) {
main.execute(join(mainType, nil()));
} else {
// Opportunistically parse arguments and convert to ints.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.enso.runner;

import org.enso.distribution.Environment;

public class RunnerEnvironment implements Environment {}
32 changes: 28 additions & 4 deletions engine/runner/src/main/java/org/enso/runner/RunnerLogging.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.enso.distribution.DistributionManager;
import org.enso.logger.masking.Masking;
import org.enso.logging.config.LoggerSetup;
import org.slf4j.Logger;
Expand All @@ -14,6 +15,8 @@ final class RunnerLogging {
private RunnerLogging() {}

private static final Logger logger = LoggerFactory.getLogger(RunnerLogging.class);
private static final DistributionManager distributionManager =
new DistributionManager(new RunnerEnvironment());

/**
* Sets up the runner's logging service.
Expand Down Expand Up @@ -49,17 +52,38 @@ private static void setupImpl(
var success = future.get();
if (success) {
logger.trace("Connected to logging service at [{}]", connectionUri);
return;
} else {
throw new RuntimeException("Failed to connect to logging service");
}
} catch (InterruptedException | ExecutionException e) {
System.err.println(
"Failed to connect to the logging service server, " + "falling back to local logging.");
}
}
if (!setupConsoleAppender(logLevel, executorService, loggerSetup)) {
System.err.println("Failed to initialize logging infrastructure");
} else {
var future =
executorService.submit(
() ->
loggerSetup.setup(
logLevel,
distributionManager.detectPaths().logs(),
"enso-cli",
loggerSetup.getConfig()));
try {
var success = future.get();
if (!success) {
System.err.println("Failed to initialize logging from the configuration");
} else {
return;
}
} catch (InterruptedException | ExecutionException e) {
System.err.println(
"Failed to initialize logging from the configuration due to internal exception: "
+ e.getMessage());
}
System.err.println("Attempting to fallback logging to console only");
if (!setupConsoleAppender(logLevel, executorService, loggerSetup)) {
System.err.println("Failed to initialize logging infrastructure");
}
}
}

Expand Down
28 changes: 28 additions & 0 deletions engine/runner/src/main/resources/application.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# CLI's application.conf

logging-service {
logger {
akka.actor = info
akka.event = error
akka.io = error
akka.stream = error
}
appenders = [
{
name = "file",
pattern = "[%level{lowercase=true}] [%d{yyyy-MM-dd'T'HH:mm:ssXXX}] [%logger] %msg%n"
},
{
name = "console"
pattern = "[%level{lowercase=true}] [%d{yyyy-MM-dd'T'HH:mm:ssXXX}] [%logger] %msg%n%nopex"
}
]
default-appender = console
default-appender = ${?ENSO_APPENDER_DEFAULT}
log-to-file {
enable = true
enable = ${?ENSO_LOG_TO_FILE}
log-level = trace
log-level = ${?ENSO_LOG_TO_FILE_LOG_LEVEL}
}
}
Loading