Skip to content

Commit 84c1f99

Browse files
Add documentation
1 parent 018c470 commit 84c1f99

File tree

1 file changed

+241
-0
lines changed

1 file changed

+241
-0
lines changed

sample-spring-boot/README.md

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
# Spring Boot Sample Application
2+
3+
This sample application shows how cf-java-logging-support can be used in an application.
4+
It features a small Spring Boot application to showcase various features provided by the library.
5+
The application provides a Rest API to trigger several actions.
6+
See section [Features](#features) for details.
7+
8+
## Getting Started
9+
10+
This sample application is contained in the Maven module sample-spring-boot.
11+
It can be built with a simple `mvn install`.
12+
A minimal CF application manifest is provided in [manifest.yml.](manifest.yml)
13+
This allows to deploy the newly built app with `cf push`, provided a login to a CF instance.
14+
15+
### Changing the Credentials
16+
17+
This sample application contains several credentials to secure the access.
18+
The credentials should be changed, before the application is built and deployed.
19+
20+
#### Basic Authentication
21+
22+
Every Rest endpoint is secured with Basic Authentication.
23+
The corresponding username and password are contained in the [application.yml](src/main/resources/application.yml).
24+
Please change the values of `username` and `password` in the following section of that file.
25+
26+
```yaml
27+
auth:
28+
basic:
29+
username: user
30+
password: secret
31+
```
32+
33+
#### Keystore Configuration
34+
35+
This sample application uses a JKS keystore.
36+
It is created by Maven, when it cannot be found in `target/generated-resources/keystore/token_keystore.jks`
37+
The credentials to that keystore as well as the dname for the generated key can be configured as Maven properties in the [pom.xml](pom.xml):
38+
39+
```xml
40+
<properties>
41+
<!-- other properties -->
42+
<keystore.token.store_password>0bzhBRNUXBR5</keystore.token.store_password>
43+
<keystore.token.key_password>0bzhBRNUXBR5</keystore.token.key_password>
44+
<keystore.token.key_alias>jwt-token</keystore.token.key_alias>
45+
<keystore.token.dname>CN=cf-java-logging-support, OU=None, O=SAP, L=Unknown, ST=Unknown, C=Unknown</keystore.token.dname>
46+
</properties>
47+
```
48+
49+
**Note:** Creating the keystore with Maven means, that it will be deleted by `mvn clean` and a new key pair will be created with `mvn install`.
50+
51+
### Changing the Logging Backend
52+
53+
This sample application can use both supported logging backends.
54+
By default it will use logback, which is configured by [logback.xml](src/main/resources/logback.xml).
55+
56+
Log4j2 can be chosen as backend by using the corresponding Maven profile:
57+
58+
```bash
59+
mvn install -Plog4j2
60+
```
61+
62+
The configuration file is [log4j2.xml](src/main/resources/log4j2.xml) in that case.
63+
64+
## Features
65+
66+
This sample application offers a Rest API with several endpoints to show different features of cf-java-logging-support.
67+
A summary of the endpoints is given in the following table.
68+
Detailed descriptions are given in later sections.
69+
70+
| Feature | Endpoint | Request Parameter |
71+
|---------|----------|-------------------|
72+
| [Generate Log Message](#generating-log-messages) | `POST /log/{logger}/{logLevel}` <br /><dl><dt>`{logger}`</dt><dd>the logger name, usually a class name</dd><dt>`{logLevel}`</dt><dd>the log level, one of `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`</dd></dl>| <dl><dt>`m=message`_(optional)_</dt><dd>the message to log</dd></dl> |
73+
| [Create JWT for dynamic log level](#creating-tokens) | `GET /token/{logLevel}` <br /><dl><dt>`{logLevel}`</dt><dd>the dynamic log level, one of `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`</dd></dl>| <dl><dt>`p=packagenames` _(optional)_</dt><dd>a comma-separated list of package names</dd><dt>`exp=unixEpoch` _(optional)_</dt><dd>the expiry time in milliseconds since Unix epoch</dd></dl>|
74+
| [Get public key for JWT verification](#get-public-key) | `GET /publickey` ||
75+
76+
### Generating Log Messages
77+
78+
This sample application allows the generation of log messages triggered by an HTTP request.
79+
Users can send a POST request containing the logger, the required log level and optionally the message to log.
80+
This allows testing the logging configuration with respect to packages and logging levels.
81+
82+
**Example:**
83+
84+
```bash
85+
$ curl -X POST -u user:secret localhost:8080/log/test/info
86+
Generated info log with message: "This is the default log message!".
87+
```
88+
89+
```json
90+
{
91+
"written_at":"2021-02-13T10:25:18.673Z",
92+
"written_ts":1613211918673355000,
93+
"tenant_id":"-",
94+
"component_id":"-",
95+
"component_name":"-",
96+
"organization_name":"-",
97+
"component_type":"application",
98+
"space_name":"-",
99+
"component_instance":"0",
100+
"organization_id":"-",
101+
"correlation_id":"81c759fd-4433-4d06-bddf-c5c30199c49b",
102+
"space_id":"-",
103+
"container_id":"-",
104+
"tenant_subdomain":"-",
105+
"type":"log",
106+
"logger":"test",
107+
"thread":"http-nio-8080-exec-2",
108+
"level":"INFO",
109+
"categories":[],
110+
"msg":"This is the default log message!"
111+
}
112+
{
113+
"written_at":"2021-02-13T10:25:18.676Z",
114+
"written_ts":1613211918677807000,
115+
"tenant_id":"-",
116+
"component_id":"-",
117+
"component_name":"-",
118+
"organization_name":"-",
119+
"component_type":"application",
120+
"space_name":"-",
121+
"component_instance":"0",
122+
"organization_id":"-",
123+
"correlation_id":"81c759fd-4433-4d06-bddf-c5c30199c49b",
124+
"space_id":"-",
125+
"container_id":"-",
126+
"tenant_subdomain":"-",
127+
"type":"request",
128+
"request":"/log/test/info",
129+
"referer":"-",
130+
"response_sent_at":"2021-02-13T10:25:18.676Z",
131+
"response_status":200,
132+
"method":"POST",
133+
"response_size_b":68,
134+
"request_size_b":-1,
135+
"remote_port":"redacted",
136+
"layer":"[SERVLET]",
137+
"remote_host":"redacted",
138+
"x_forwarded_for":"-",
139+
"remote_user":"redacted",
140+
"protocol":"HTTP/1.1",
141+
"remote_ip":"redacted",
142+
"response_content_type":"text/plain;charset=ISO-8859-1",
143+
"request_received_at":"2021-02-13T10:25:18.665Z",
144+
"response_time_ms":10.78147,
145+
"direction":"IN"
146+
}
147+
```
148+
149+
Note, that the request generates the default log message, that is also contained in the HTTP response and additionally a request log.
150+
Since this example was executed locally, the CF metadata is empty.
151+
152+
A custom message can be given as well:
153+
154+
```bash
155+
$ curl -X POST -u user:secret 'localhost:8080/log/test/info?m=Hello+cf-java-logging-support!'
156+
Generated info log with message: "Hello cf-java-logging-support!".
157+
```
158+
159+
Note the quotes for bash and the HTTP encoding of the whitespace in the message.
160+
161+
### Dynamic Log Levels
162+
163+
This sample-application supports dynamic log levels with package support.
164+
This feature is documented in detail in the [project wiki.](https://github.com/SAP/cf-java-logging-support/wiki/Dynamic-Log-Levels)
165+
It allows to change the log level by sending the HTTP header `SAP_LOG_LEVEL` with an appropriate JWT.
166+
Since it is not straight forward to generate such a token, there is an endpoint to create such a JWT.
167+
168+
#### Creating Tokens
169+
170+
The generated token needs to contain three things:
171+
172+
* the log level to apply
173+
* the package names or prefixes to use
174+
* an expiration timestamp
175+
176+
The log level is taken as path variable.
177+
Since package names and expiration timestamp are optional, they can be specified as request parameters.
178+
JWTs to be used with this sample application require a package name, but an empty string is allowed.
179+
If no expiration timestamp is provided the application will take the current timestamp and add the default period as configure in `defaults.token.expiration: P2D` in [application.yml](src/main/resources/application.yml) (two days by default).
180+
You can change the JWT issuer with property `defaults.token.issuer: your-issuer` in [application.yml](src/main/resources/application.yml).
181+
182+
**Example:**
183+
184+
```bash
185+
$ curl -u user:secret 'localhost:8080/token/DEBUG?p=com,org'
186+
eyJraWQiOiJqd3QtdG9rZW4iLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJsZXZlbCI6IkRFQlVHIiwiaXNzIjoic2FtcGxlLWFwcC1zcHJpbmctYm9vdCIsImV4cCI6MTYxMzM4Njg2MCwicGFja2FnZXMiOiJjb20sb3JnIiwiaWF0IjoxNjEzMjE0MDYwfQ.YtTk8VnMGN2i3SRLK8GRCDfgQcnAQL04IqojZdVYwEJFCezJsot20MYN-WpAWizVVV3midunnBrNzR3_dByK2gRzTQGGE9rXh4KpLw_4UM6XUJTgpMU8yzqt4pCBT-wpMbJ8UOKbT2RCdqOU1oWJL6rggxi5hGBItTvu0PZzjSG3Zv1eIvDKZcNF9pq4F1r8H2og1Mun28o1r-J5SCURjmolunKDNp4e6fsGSeUttbT5EulIcfHcM9nD4Byyywc2Khs0H13YPqAjdxxFcu_5fYp8JFgbns2Lo5PYjMbY8nxnuZFJmILwXHHRtAoxrcSbpSzFRtZfQsI4earGBGSyog
187+
```
188+
189+
The response payload decodes to:
190+
191+
```json
192+
{
193+
"level": "DEBUG",
194+
"iss": "sample-app-spring-boot",
195+
"exp": 1613386860,
196+
"packages": "com,org",
197+
"iat": 1613214060
198+
}
199+
```
200+
201+
**Note:** cf-java-logging-support requires the log level to be one of `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE` in all-caps.
202+
203+
204+
#### Using Tokens
205+
206+
The tokens created with the token endpoint can be used as HTTP headers on all endpoints of the application.
207+
We use the token created in the previous section to post a new log message.
208+
Note, that the package name prefixes `org` and `com` will trigger debug logs from many classes, especially Spring (org.springframework.\*) and this libray (com.sap.\*).
209+
210+
```bash
211+
$ curl -X POST -u user:secret 'localhost:8080/log/test/info?m=Hello+cf-java-logging-support!' -H 'SAP-LOG-LEVEL: eyJraWQiOiJqd3QtdG9rZW4iLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJsZXZlbCI6IkRFQlVHIiwiaXNzIjoic2FtcGxlLWFwcC1zcHJpbmctYm9vdCIsImV4cCI6MTYxMzM4Njg2MCwicGFja2FnZXMiOiJjb20sb3JnIiwiaWF0IjoxNjEzMjE0MDYwfQ.YtTk8VnMGN2i3SRLK8GRCDfgQcnAQL04IqojZdVYwEJFCezJsot20MYN-WpAWizVVV3midunnBrNzR3_dByK2gRzTQGGE9rXh4KpLw_4UM6XUJTgpMU8yzqt4pCBT-wpMbJ8UOKbT2RCdqOU1oWJL6rggxi5hGBItTvu0PZzjSG3Zv1eIvDKZcNF9pq4F1r8H2og1Mun28o1r-J5SCURjmolunKDNp4e6fsGSeUttbT5EulIcfHcM9nD4Byyywc2Khs0H13YPqAjdxxFcu_5fYp8JFgbns2Lo5PYjMbY8nxnuZFJmILwXHHRtAoxrcSbpSzFRtZfQsI4earGBGSyog'
212+
Generated info log with message: "Hello cf-java-logging-support!".
213+
```
214+
215+
```json
216+
{ "written_at":"2021-02-13T11:01:25.914Z","written_ts":1613214085914635000,"tenant_id":"-","component_id":"-","component_name":"-","organization_name":"-","component_type":"application","space_name":"-","component_instance":"0","organization_id":"-","dynamic_log_level_prefixes":"com,org","correlation_id":"c7a92c5e-1e69-4ef9-98ad-8cca27accab9","space_id":"-","container_id":"-","dynamic_log_level":"DEBUG","tenant_subdomain":"-","type":"log","logger":"org.springframework.web.servlet.DispatcherServlet","thread":"http-nio-8080-exec-6","level":"DEBUG","categories":[],"msg":"POST \"/log/test/info?m=Hello+cf-java-logging-support!\", parameters={masked}" }
217+
{ "written_at":"2021-02-13T11:01:25.915Z","written_ts":1613214085915196000,"tenant_id":"-","component_id":"-","component_name":"-","organization_name":"-","component_type":"application","space_name":"-","component_instance":"0","organization_id":"-","dynamic_log_level_prefixes":"com,org","correlation_id":"c7a92c5e-1e69-4ef9-98ad-8cca27accab9","space_id":"-","container_id":"-","dynamic_log_level":"DEBUG","tenant_subdomain":"-","type":"log","logger":"org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping","thread":"http-nio-8080-exec-6","level":"DEBUG","categories":[],"msg":"Mapped to com.sap.hcp.cf.logging.sample.springboot.controller.LogController#generateLog(String, String, String)" }
218+
{ "written_at":"2021-02-13T11:01:25.915Z","written_ts":1613214085915814000,"tenant_id":"-","component_id":"-","component_name":"-","organization_name":"-","component_type":"application","space_name":"-","component_instance":"0","organization_id":"-","dynamic_log_level_prefixes":"com,org","correlation_id":"c7a92c5e-1e69-4ef9-98ad-8cca27accab9","space_id":"-","container_id":"-","dynamic_log_level":"DEBUG","tenant_subdomain":"-","type":"log","logger":"test","thread":"http-nio-8080-exec-6","level":"INFO","categories":[],"msg":"Hello cf-java-logging-support!" }
219+
{ "written_at":"2021-02-13T11:01:25.916Z","written_ts":1613214085916279000,"tenant_id":"-","component_id":"-","component_name":"-","organization_name":"-","component_type":"application","space_name":"-","component_instance":"0","organization_id":"-","dynamic_log_level_prefixes":"com,org","correlation_id":"c7a92c5e-1e69-4ef9-98ad-8cca27accab9","space_id":"-","container_id":"-","dynamic_log_level":"DEBUG","tenant_subdomain":"-","type":"log","logger":"org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor","thread":"http-nio-8080-exec-6","level":"DEBUG","categories":[],"msg":"Using 'text/plain', given [*/*] and supported [text/plain, */*, application/json, application/*+json]" }
220+
{ "written_at":"2021-02-13T11:01:25.916Z","written_ts":1613214085916702000,"tenant_id":"-","component_id":"-","component_name":"-","organization_name":"-","component_type":"application","space_name":"-","component_instance":"0","organization_id":"-","dynamic_log_level_prefixes":"com,org","correlation_id":"c7a92c5e-1e69-4ef9-98ad-8cca27accab9","space_id":"-","container_id":"-","dynamic_log_level":"DEBUG","tenant_subdomain":"-","type":"log","logger":"org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor","thread":"http-nio-8080-exec-6","level":"DEBUG","categories":[],"msg":"Writing [\"Generated info log with message: \"Hello cf-java-logging-support!\".\"]" }
221+
{ "written_at":"2021-02-13T11:01:25.917Z","written_ts":1613214085917217000,"tenant_id":"-","component_id":"-","component_name":"-","organization_name":"-","component_type":"application","space_name":"-","component_instance":"0","organization_id":"-","dynamic_log_level_prefixes":"com,org","correlation_id":"c7a92c5e-1e69-4ef9-98ad-8cca27accab9","space_id":"-","container_id":"-","dynamic_log_level":"DEBUG","tenant_subdomain":"-","type":"log","logger":"org.springframework.security.web.header.writers.HstsHeaderWriter","thread":"http-nio-8080-exec-6","level":"DEBUG","categories":[],"msg":"Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@279e2b53" }
222+
{ "written_at":"2021-02-13T11:01:25.917Z","written_ts":1613214085917528000,"tenant_id":"-","component_id":"-","component_name":"-","organization_name":"-","component_type":"application","space_name":"-","component_instance":"0","organization_id":"-","dynamic_log_level_prefixes":"com,org","correlation_id":"c7a92c5e-1e69-4ef9-98ad-8cca27accab9","space_id":"-","container_id":"-","dynamic_log_level":"DEBUG","tenant_subdomain":"-","type":"log","logger":"org.springframework.security.web.context.HttpSessionSecurityContextRepository","thread":"http-nio-8080-exec-6","level":"DEBUG","categories":[],"msg":"SecurityContext 'org.springframework.security.core.context.SecurityContextImpl@442b5a9f: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@442b5a9f: Principal: org.springframework.security.core.userdetails.User@36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_USER' stored to HttpSession: 'org.apache.catalina.session.StandardSessionFacade@488b143c" }
223+
{ "written_at":"2021-02-13T11:01:25.918Z","written_ts":1613214085918181000,"tenant_id":"-","component_id":"-","component_name":"-","organization_name":"-","component_type":"application","space_name":"-","component_instance":"0","organization_id":"-","dynamic_log_level_prefixes":"com,org","correlation_id":"c7a92c5e-1e69-4ef9-98ad-8cca27accab9","space_id":"-","container_id":"-","dynamic_log_level":"DEBUG","tenant_subdomain":"-","type":"log","logger":"org.springframework.web.servlet.DispatcherServlet","thread":"http-nio-8080-exec-6","level":"DEBUG","categories":[],"msg":"Completed 200 OK" }
224+
{ "written_at":"2021-02-13T11:01:25.918Z","written_ts":1613214085918645000,"tenant_id":"-","component_id":"-","component_name":"-","organization_name":"-","component_type":"application","space_name":"-","component_instance":"0","organization_id":"-","dynamic_log_level_prefixes":"com,org","correlation_id":"c7a92c5e-1e69-4ef9-98ad-8cca27accab9","space_id":"-","container_id":"-","dynamic_log_level":"DEBUG","tenant_subdomain":"-","type":"request","request":"/log/test/info?m=Hello+cf-java-logging-support!","referer":"-","response_sent_at":"2021-02-13T11:01:25.918Z","response_status":200,"method":"POST","response_size_b":66,"request_size_b":-1,"remote_port":"redacted","layer":"[SERVLET]","remote_host":"redacted","x_forwarded_for":"-","remote_user":"redacted","protocol":"HTTP/1.1","remote_ip":"redacted","response_content_type":"text/plain;charset=ISO-8859-1","request_received_at":"2021-02-13T11:01:25.914Z","response_time_ms":3.90267,"direction":"IN"}
225+
```
226+
227+
As you can see there are now several debug messages from Spring, that are usually suppressed by the logging configuration but are now written due to the JWT configuration.
228+
229+
#### Get Public Key
230+
231+
This sample application can be used as a JWT generator for applications in production.
232+
For the configuration of those application cf-java-logging-support needs the public key to validate the JWT signature.
233+
This public key can be obtained
234+
235+
```bash
236+
$ curl -u user:secret 'localhost:8080/publickey'
237+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk/a5ZKvQ0voLi29klo5GCtN40JpscGud5diz2y5mNVCMvU6rdE+yNMs5zfgjy2PhR0TLXWfZrwHeX75dhC49hJup39pClv83FJWVbu6ScWNQUGYgdUY5zGkFcBayZlt1yXybQaCUtC8ksHe+QOAUW9Y43nPa8/vznH+zbROlF/kSHIjegcr0GF6ZOLMBAj+9p6Xp+kZxsFUgnqgIZWUp4YI3+j2xDuBgNptZbjUg7WsqEU/u+CA5uCyjGVriq++qSW1fj1A0C29uj1+n3IqrMlL2MdMQayS/5ppyrjApsSYDG56wQEAOrOKaSeBsZexIvIdhQ12+5SkqwPlQGCUHpQIDAQAB
238+
```
239+
240+
**Note:** If this application is used this way you may want to fix the keystore and not accidentally delete it with `mvn clean`.
241+
You can add your keystore as `src/main/resoures/token_keystore.jks`, which will override the automatically created keystore.

0 commit comments

Comments
 (0)