95dc52c85c020d39c54f11675a6ca38dfcb66b19
[sdc.git] /
1 /*
2  * Copyright © 2016-2017 European Support Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.openecomp.sdc.logging;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.InputStreamReader;
22 import java.net.InetAddress;
23 import java.net.UnknownHostException;
24 import java.nio.charset.StandardCharsets;
25 import java.util.Properties;
26 import java.util.UUID;
27 import java.util.concurrent.atomic.AtomicLong;
28 import java.util.prefs.BackingStoreException;
29 import java.util.prefs.Preferences;
30
31 /**
32  * Collect information the is required for logging, but should not concern the business code of an application. For
33  * example, host name and IP address.
34  *
35  * @author evitaliy
36  * @since 04 Mar 2018
37  */
38 @SuppressWarnings({"UseOfSystemOutOrSystemErr", "CallToPrintStackTrace", "squid:S106", "squid:S1148"})
39 public class GlobalLoggingContext {
40
41     private static final String APPLICATION_ID_KEY = "ApplicationId";
42
43     private static final String CONFIGURATION_RESOURCE = "META-INF/logging/logger.properties";
44
45     @SuppressWarnings("squid:S1075")
46     private static final String ID_PREFERENCES_PATH = "/logging/instance/uuid";
47
48     private static final String APP_DISTINGUISHER_KEY = "app.distinguisher";
49
50     // should be cashed to avoid low-level call, but with a timeout to account for IP or FQDN changes
51     private static final HostAddressCache HOST_ADDRESS = new HostAddressCache();
52
53     private static final String DISTINGUISHER;
54
55     private static final String APPLICATION_ID;
56
57     private static final String INSTANCE_ID;
58
59     static {
60         APPLICATION_ID = System.getProperty(APPLICATION_ID_KEY);
61         DISTINGUISHER = readDistinguisher();
62         INSTANCE_ID = readInstanceId();
63     }
64
65     private GlobalLoggingContext() { /* prevent instantiation */ }
66
67     public static String getApplicationId() {
68         return APPLICATION_ID;
69     }
70
71     /**
72      * A distinguisher to allow separation of logs created by applications running with the same configuration, but
73      * different class-loaders. For instance, when multiple web application are running in the same container and their
74      * logger configuration is passed at the JVM level.
75      *
76      * @return application distinguisher defined in a properties file
77      */
78     public static String getDistinguisher() {
79         return DISTINGUISHER;
80     }
81
82     /**
83      * A unique ID of the logging entity. Is useful to distinguish between different nodes of the same application. It
84      * is assumed, that the node can be re-started, in which case the unique ID must be retained.
85      *
86      * @return unique logging entity ID
87      */
88     public static String getInstanceId() {
89         return INSTANCE_ID;
90     }
91
92     /**
93      * Local host address as returned by Java runtime. A value of host address will be cached for the interval specified
94      * in {@link HostAddressCache#REFRESH_TIME}
95      *
96      * @return local host address, may be null if could not be read for some reason
97      */
98     public static InetAddress getHostAddress() {
99         return HOST_ADDRESS.get();
100     }
101
102     private static String readInstanceId() {
103
104         String appId = System.getProperty(APPLICATION_ID_KEY);
105         String key = ID_PREFERENCES_PATH + (appId == null ? "" : "/" + appId);
106
107         try {
108
109             // By default, this will be ~/.java/.userPrefs/prefs.xml
110             final Preferences preferences = Preferences.userRoot();
111             String existingId = preferences.get(key, null);
112             if (existingId != null) {
113                 return existingId;
114             }
115
116             String newId = UUID.randomUUID().toString();
117             preferences.put(key, newId);
118             preferences.flush();
119             return newId;
120
121         } catch (BackingStoreException e) {
122             e.printStackTrace();
123             // don't fail if there's a problem to use the store for some unexpected reason
124             return UUID.randomUUID().toString();
125         }
126     }
127
128     private static String readDistinguisher() {
129
130         try {
131             Properties properties = loadConfiguration();
132             return properties.getProperty(APP_DISTINGUISHER_KEY, "");
133         } catch (IOException e) {
134             e.printStackTrace(); // can't write to a log
135             return "";
136         }
137     }
138
139     private static Properties loadConfiguration() throws IOException {
140
141         Properties properties = new Properties();
142
143         try (InputStream is = Thread.currentThread().getContextClassLoader()
144             .getResourceAsStream(CONFIGURATION_RESOURCE)) {
145
146             if (is == null) {
147                 return properties;
148             }
149
150             try (InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
151                 properties.load(reader);
152                 return properties;
153             }
154         }
155     }
156
157     private static class HostAddressCache {
158
159         private static final long REFRESH_TIME = 60000L;
160
161         private final AtomicLong lastUpdated = new AtomicLong(0L);
162         private InetAddress hostAddress;
163
164         public InetAddress get() {
165
166             long current = System.currentTimeMillis();
167             if (current - lastUpdated.get() > REFRESH_TIME) {
168
169                 synchronized (this) {
170
171                     try {
172                         // set now to register the attempt even if failed
173                         lastUpdated.set(current);
174                         hostAddress = InetAddress.getLocalHost();
175                     } catch (UnknownHostException e) {
176                         e.printStackTrace(); // can't really use logging
177                         hostAddress = null;
178                     }
179                 }
180             }
181
182             return hostAddress;
183         }
184     }
185 }