///////////////////////////////////////////////////////////////////////////////

    Copyright (c) 2019, 2020 Oracle and/or its affiliates.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

///////////////////////////////////////////////////////////////////////////////

:description: Helidon Reactive Webserver Access Log
:keywords: helidon, webserver, access log

= WebServer Access Log

Access logging in Helidon is done by a dedicated module that can be
added to WebServer and configured.

Access logging is a Helidon WebServer `Service` and as such is executed
in the order it is registered with WebServer routing.
This implies that if you register it last and another `Service` or
`Handler` finishes the request, the service will not be invoked.


== Configuring Access Log in your code

Access log is configured in your code by registering it as a service with `Routing`

[source,java]
----
Routing.builder()
    .register(AccessLogSupport.create(config.get("server.access-log")))
    .get("/greet", myService)
----

The order of registration is significant - make sure `AccessLogSupport` is registered first (even before security, tracing etc.).

== Configuring Access Log in a configuration file

Access log can be configured as follows:

[source, yaml]
.Access Log configuration file
----
server:
  port: 8080
  access-log:
    format: "%h %l %u %t %r %s %b %{Referer}i"
----

All options shown above are also available programmatically when using builder.

== Configuration options

The following configuration options can be defined:

|===
|Config key     |Default value      |Builder method     |Description

|`enabled`      |`true`             |`enabled(boolean)`          |When this option is set to `false`, access logging will be disabled
|`logger-name`  |`io.helidon.webserver.AccessLog` |`loggerName(String)` |Name of the logger to use when writing log entries
|`format`       |`helidon`          |`helidonLogFormat()`, `commonLogFormat()`, `add(AccessLogEntry entry)` |Configuration of access log output,
                                                        when `helidon` is defined, the Helidon log format (see below) is used.
                                                        Can be configured to explicitly define log entries (see below as well)

|===

== Supported Log Formats

=== Supported Log Entries

The following log entries are supported in Helidon:

|===
|Config format  |Class (to use with builder)    |Description

|%h                 |`HostLogEntry`                 |IP address of the remote host
|%l                 |`UserIdLogEntry`               |Client identity, always undefined in Helidon
|%u                 |`UserLogEntry`                 |The username of logged-in user (when Security is used)
|%t                 |`TimestampLogEntry`            |The current timestamp
|%r                 |`RequestLineLogEntry`          |The request line (method, path and HTTP version)
|%s                 |`StatusLogEntry`               |The HTTP status returned to the client
|%b                 |`SizeLogEntry`                 |The response entity size (if available)
|%D                 |`TimeTakenLogEntry`            |The time taken in microseconds
|%T                 |`TimeTakenLogEntry`            |The time taken in seconds
|%{`header-name`}i  |`HeaderLogEntry`               |Value of a header (can have multiple such specification to write
                                                     multiple headers)
|===

Currently we only support the entries defined above, with NO support for free text.

=== Helidon Log Format
When format is set to `helidon`, the format used is:

`"%h %u %t %r %s %b %D"`

The entries logged:

1. IP Address
2. Username of a logged-in user
3. Timestamp
4. Request Line
5. HTTP Status code
6. Entity size
7. Time taken (microseconds)

Access log example:

----
192.168.0.104 - [18/Jun/2019:22:28:55 +0200] "GET /greet/test HTTP/1.1" 200 53
0:0:0:0:0:0:0:1 - [18/Jun/2019:22:29:00 +0200] "GET /metrics/vendor HTTP/1.1" 200 1658
0:0:0:0:0:0:0:1 jack [18/Jun/2019:22:29:07 +0200] "PUT /greet/greeting HTTP/1.1" 200 21
0:0:0:0:0:0:0:1 jill [18/Jun/2019:22:29:12 +0200] "PUT /greet/greeting HTTP/1.1" 403 0
0:0:0:0:0:0:0:1 - [18/Jun/2019:22:29:17 +0200] "PUT /greet/greeting HTTP/1.1" 401 0
----


=== Common Log Format
When format is set to `common`, the format used is:

`"%h %l %u %t %r %s %b"`

The entries logged:

1. IP Address
2. Client identity
3. Username of a logged-in user
4. Timestamp
5. Request Line
6. HTTP Status code
7. Entity size

Access log example:

----
192.168.0.104   - - [18/Jun/2019:22:28:55 +0200] "GET /greet/test HTTP/1.1" 200 53
0:0:0:0:0:0:0:1 - - [18/Jun/2019:22:29:00 +0200] "GET /metrics/vendor HTTP/1.1" 200 1658
0:0:0:0:0:0:0:1 - jack [18/Jun/2019:22:29:07 +0200] "PUT /greet/greeting HTTP/1.1" 200 21
0:0:0:0:0:0:0:1 - jill [18/Jun/2019:22:29:12 +0200] "PUT /greet/greeting HTTP/1.1" 403 0
0:0:0:0:0:0:0:1 - - [18/Jun/2019:22:29:17 +0200] "PUT /greet/greeting HTTP/1.1" 401 0
----

== Configuring Access Log with Java util logging

To support a separate file for Access log entries, Helidon provides a custom
log handler, that extends the `FileHandler`.

To log to a file `access.log` with appending records after restart, you can use the
 following configuration in `logging.properties`:

[source, properties]
.Logging configuration file
----
io.helidon.webserver.accesslog.AccessLogHandler.level=INFO
io.helidon.webserver.accesslog.AccessLogHandler.pattern=access.log
io.helidon.webserver.accesslog.AccessLogHandler.append=true

io.helidon.webserver.AccessLog.level=INFO
io.helidon.webserver.AccessLog.useParentHandlers=false
io.helidon.webserver.AccessLog.handlers=io.helidon.webserver.accesslog.AccessLogHandler
----
