Skip to content

Commit

Permalink
Add kubernetes-log4j module
Browse files Browse the repository at this point in the history
This module adds the ability to Log4j Core to use Kubernetes attributes
in a configuration file.

It is a cleaned-up version of the
`org.apache.logging.log4j:log4j-kubernetes`.

As explained in #5682, it does make more sense to host is here since:

 * it only depends on a very stable `StrLookup` dependency from
   `log4j-core`,
 * the number and kind of properties available through
   `kubernetes-client` depend on its version.
  • Loading branch information
rgoers authored and ppkarwasz committed Jan 19, 2024
1 parent e7f734b commit fb56ca6
Show file tree
Hide file tree
Showing 11 changed files with 1,249 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#### Dependency Upgrade

#### New Features
* Add a `kubernetes-log4j` module to lookup Kubernetes attributes in a Log4j Core configuration.

#### _**Note**_: Breaking changes

Expand Down
89 changes: 89 additions & 0 deletions log4j/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2015 Red Hat, Inc.
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client-project</artifactId>
<version>6.11-SNAPSHOT</version>
</parent>

<artifactId>kubernetes-log4j</artifactId>
<packaging>jar</packaging>
<name>Fabric8 :: Kubernetes :: Log4j Core components</name>
<description>Provides a lookup to use Kubernetes attributes in a Log4j Core configuration.</description>

<properties>
<osgi.export>io.fabric8.kubernetes.log4j.*</osgi.export>
<osgi.import>*</osgi.import>
</properties>

<dependencies>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client</artifactId>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-model-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<!-- Replace `jar:jar` execution with `bundle:bundle` -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>default-jar</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<executions>
<execution>
<id>generate-osgi-bundle</id>
<goals>
<goal>bundle</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* Copyright (C) 2015 Red Hat, Inc.
*
* 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.
*/
package io.fabric8.kubernetes.log4j.lookup;

import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.ConfigBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientBuilder;

/**
* Builds a Kubernetes Client.
*/
class ClientBuilder {

public KubernetesClient createClient() {
final Config config = kubernetesClientConfig();
return config != null ? new KubernetesClientBuilder()
.withConfig(config).build() : null;
}

private Config kubernetesClientConfig() {
Config base = null;
try {
base = Config.autoConfigure(null);
} catch (Exception ex) {
if (ex instanceof NullPointerException) {
return null;
}
}
final ClientProperties props = new ClientProperties(base);
final Config properties = new ConfigBuilder(base)
.withApiVersion(props.getApiVersion())
.withCaCertData(props.getCaCertData())
.withCaCertFile(props.getCaCertFile())
.withClientCertData(props.getClientCertData())
.withClientCertFile(props.getClientCertFile())
.withClientKeyAlgo(props.getClientKeyAlgo())
.withClientKeyData(props.getClientKeyData())
.withClientKeyFile(props.getClientKeyFile())
.withClientKeyPassphrase(props.getClientKeyPassphrase())
.withConnectionTimeout(props.getConnectionTimeout())
.withHttpProxy(props.getHttpProxy())
.withHttpsProxy(props.getHttpsProxy())
.withMasterUrl(props.getMasterUrl())
.withNamespace(props.getNamespace())
.withNoProxy(props.getNoProxy())
.withPassword(props.getPassword())
.withProxyPassword(props.getProxyPassword())
.withProxyUsername(props.getProxyUsername())
.withRequestTimeout(props.getRequestTimeout())
.withTrustCerts(props.isTrustCerts())
.withUsername(props.getUsername())
.build();
return properties;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/**
* Copyright (C) 2015 Red Hat, Inc.
*
* 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.
*/
package io.fabric8.kubernetes.log4j.lookup;

import io.fabric8.kubernetes.client.Config;
import org.apache.logging.log4j.util.PropertiesUtil;

import java.time.Duration;

/**
* Obtains properties used to configure the Kubernetes client.
*/
class ClientProperties {

private static final String[] PREFIXES = { "log4j2.kubernetes.client.", "spring.cloud.kubernetes.client." };
private static final String API_VERSION = "apiVersion";
private static final String CA_CERT_FILE = "caCertFile";
private static final String CA_CERT_DATA = "caCertData";
private static final String CLIENT_CERT_FILE = "clientCertFile";
private static final String CLIENT_CERT_DATA = "clientCertData";
private static final String CLIENT_KEY_FILE = "clientKeyFile";
private static final String CLIENT_KEY_DATA = "clientKeyData";
private static final String CLIENT_KEY_ALGO = "clientKeyAlgo";
private static final String CLIENT_KEY_PASSPHRASE = "clientKeyPassphrase";
private static final String CONNECTION_TIMEOUT = "connectionTimeout";
private static final String HTTP_PROXY = "httpProxy";
private static final String HTTPS_PROXY = "httpsProxy";
private static final String LOGGING_INTERVAL = "loggingInterval";
private static final String MASTER_URL = "masterUrl";
private static final String NAMESPACE = "namespace";
private static final String NO_PROXY = "noProxy";
private static final String PASSWORD = "password";
private static final String PROXY_USERNAME = "proxyUsername";
private static final String PROXY_PASSWORD = "proxyPassword";
private static final String REQUEST_TIMEOUT = "requestTimeout";
private static final String TRUST_CERTS = "trustCerts";
private static final String USERNAME = "username";
private static final String WATCH_RECONNECT_INTERVAL = "watchReconnectInterval";
private static final String WATCH_RECONNECT_LIMIT = "watchReconnectLimit";

private final PropertiesUtil props = PropertiesUtil.getProperties();
private final Config base;

public ClientProperties(final Config base) {
this.base = base;
}

public String getApiVersion() {
return props.getStringProperty(PREFIXES, API_VERSION, base::getApiVersion);
}

public String getCaCertFile() {
return props.getStringProperty(PREFIXES, CA_CERT_FILE, base::getCaCertFile);
}

public String getCaCertData() {
return props.getStringProperty(PREFIXES, CA_CERT_DATA, base::getCaCertData);
}

public String getClientCertFile() {
return props.getStringProperty(PREFIXES, CLIENT_CERT_FILE, base::getClientCertFile);
}

public String getClientCertData() {
return props.getStringProperty(PREFIXES, CLIENT_CERT_DATA, base::getClientCertData);
}

public String getClientKeyFile() {
return props.getStringProperty(PREFIXES, CLIENT_KEY_FILE, base::getClientKeyFile);
}

public String getClientKeyData() {
return props.getStringProperty(PREFIXES, CLIENT_KEY_DATA, base::getClientKeyData);
}

public String getClientKeyAlgo() {
return props.getStringProperty(PREFIXES, CLIENT_KEY_ALGO, base::getClientKeyAlgo);
}

public String getClientKeyPassphrase() {
return props.getStringProperty(PREFIXES, CLIENT_KEY_PASSPHRASE, base::getClientKeyPassphrase);
}

public int getConnectionTimeout() {
final Duration timeout = props.getDurationProperty(PREFIXES, CONNECTION_TIMEOUT, null);
if (timeout != null) {
return (int) timeout.toMillis();
}
return base.getConnectionTimeout();
}

public String getHttpProxy() {
return props.getStringProperty(PREFIXES, HTTP_PROXY, base::getHttpProxy);
}

public String getHttpsProxy() {
return props.getStringProperty(PREFIXES, HTTPS_PROXY, base::getHttpsProxy);
}

public int getLoggingInterval() {
final Duration interval = props.getDurationProperty(PREFIXES, LOGGING_INTERVAL, null);
if (interval != null) {
return (int) interval.toMillis();
}
return base.getLoggingInterval();
}

public String getMasterUrl() {
return props.getStringProperty(PREFIXES, MASTER_URL, base::getMasterUrl);
}

public String getNamespace() {
return props.getStringProperty(PREFIXES, NAMESPACE, base::getNamespace);
}

public String[] getNoProxy() {
final String result = props.getStringProperty(PREFIXES, NO_PROXY, null);
if (result != null) {
return result.replace("\\s", "").split(",");
}
return base.getNoProxy();
}

public String getPassword() {
return props.getStringProperty(PREFIXES, PASSWORD, base::getPassword);
}

public String getProxyUsername() {
return props.getStringProperty(PREFIXES, PROXY_USERNAME, base::getProxyUsername);
}

public String getProxyPassword() {
return props.getStringProperty(PREFIXES, PROXY_PASSWORD, base::getProxyPassword);
}

public int getRequestTimeout() {
final Duration interval = props.getDurationProperty(PREFIXES, REQUEST_TIMEOUT, null);
if (interval != null) {
return (int) interval.toMillis();
}
return base.getRequestTimeout();
}

public Boolean isTrustCerts() {
return props.getBooleanProperty(PREFIXES, TRUST_CERTS, base::isTrustCerts);
}

public String getUsername() {
return props.getStringProperty(PREFIXES, USERNAME, base::getUsername);
}

public int getWatchReconnectInterval() {
final Duration interval = props.getDurationProperty(PREFIXES, WATCH_RECONNECT_INTERVAL, null);
if (interval != null) {
return (int) interval.toMillis();
}
return base.getWatchReconnectInterval();
}

public int getWatchReconnectLimit() {
final Duration interval = props.getDurationProperty(PREFIXES, WATCH_RECONNECT_LIMIT, null);
if (interval != null) {
return (int) interval.toMillis();
}
return base.getWatchReconnectLimit();
}
}

0 comments on commit fb56ca6

Please sign in to comment.