Skip to content

Commit

Permalink
Add client metadata header
Browse files Browse the repository at this point in the history
  • Loading branch information
swallez committed Jan 25, 2022
1 parent 8183ca2 commit a477ed0
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you 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 co.elastic.clients.transport.rest_client;

// Copied verbatim from https://github.com/elastic/jvm-languages-sniffer

import java.lang.reflect.Field;
import java.lang.reflect.Method;

class LanguageRuntimeVersions {

/**
* Returns runtime information by looking up classes identifying non-Java JVM
* languages and appending a key with their name and their major.minor version, if available
*/
public static String getRuntimeMetadata() {
StringBuilder s = new StringBuilder();
String version;

version = kotlinVersion();
if (version != null) {
s.append(",kt=").append(version);
}

version = scalaVersion();
if (version != null) {
s.append(",sc=").append(version);
}

version = clojureVersion();
if (version != null) {
s.append(",clj=").append(version);
}

version = groovyVersion();
if (version != null) {
s.append(",gy=").append(version);
}

version = jRubyVersion();
if (version != null) {
s.append(",jrb=").append(version);
}

return s.toString();
}

public static String kotlinVersion() {
// KotlinVersion.CURRENT.toString()
return keepMajorMinor(getStaticField("kotlin.KotlinVersion", "CURRENT"));
}

public static String scalaVersion() {
// scala.util.Properties.versionNumberString()
return keepMajorMinor(callStaticMethod("scala.util.Properties", "versionNumberString"));
}

public static String clojureVersion() {
// (clojure-version) which translates to
// clojure.core$clojure_version.invokeStatic()
return keepMajorMinor(callStaticMethod("clojure.core$clojure_version", "invokeStatic"));
}

public static String groovyVersion() {
// groovy.lang.GroovySystem.getVersion()
// There's also getShortVersion(), but only since Groovy 3.0.1
return keepMajorMinor(callStaticMethod("groovy.lang.GroovySystem", "getVersion"));
}

public static String jRubyVersion() {
// org.jruby.runtime.Constants.VERSION
return keepMajorMinor(getStaticField("org.jruby.runtime.Constants", "VERSION"));
}

private static String getStaticField(String className, String fieldName) {
Class<?> clazz;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
return null;
}

try {
Field field = clazz.getField(fieldName);
return field.get(null).toString();
} catch (Exception e) {
return ""; // can't get version information
}
}

private static String callStaticMethod(String className, String methodName) {
Class<?> clazz;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
return null;
}

try {
Method m = clazz.getMethod(methodName);
return m.invoke(null).toString();
} catch (Exception e) {
return ""; // can't get version information
}
}

static String keepMajorMinor(String version) {
if (version == null) {
return null;
}

int firstDot = version.indexOf('.');
int secondDot = version.indexOf('.', firstDot + 1);
if (secondDot < 0) {
return version;
} else {
return version.substring(0, secondDot);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

import co.elastic.clients.transport.TransportOptions;
import co.elastic.clients.transport.Version;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.util.VersionInfo;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.WarningsHandler;

Expand Down Expand Up @@ -107,6 +109,9 @@ public RequestOptions.Builder restClientRequestOptionsBuilder() {

@Override
public TransportOptions.Builder addHeader(String name, String value) {
if (name.equalsIgnoreCase(CLIENT_META)) {
return this;
}
if (name.equalsIgnoreCase(USER_AGENT)) {
// We must filter out our own user-agent from the options or they'll end up as multiple values for the header
RequestOptions options = builder.build();
Expand Down Expand Up @@ -159,6 +164,7 @@ public RestClientOptions build() {
}

private static final String USER_AGENT = "User-Agent";
private static final String CLIENT_META = "X-Elastic-Client-Meta";

static RestClientOptions initialOptions() {
String ua = String.format(
Expand All @@ -171,8 +177,41 @@ static RestClientOptions initialOptions() {
return new RestClientOptions(
RequestOptions.DEFAULT.toBuilder()
.addHeader(USER_AGENT, ua)
.addHeader(CLIENT_META, getClientMeta())
.addHeader("Accept", RestClientTransport.JsonContentType.toString())
.build()
);
}

private static String getClientMeta() {

VersionInfo httpClientVersion = null;
try {
httpClientVersion = VersionInfo.loadVersionInfo(
"org.apache.http.nio.client",
HttpAsyncClientBuilder.class.getClassLoader()
);
} catch (Exception e) {
// Keep unknown
}

// Use a single 'p' suffix for all prerelease versions (snapshot, beta, etc).
String metaVersion = Version.VERSION == null ? "" : Version.VERSION.toString();
int dashPos = metaVersion.indexOf('-');
if (dashPos > 0) {
metaVersion = metaVersion.substring(0, dashPos) + "p";
}

// service, language, transport, followed by additional information
return "es="
+ metaVersion
+ ",jv="
+ System.getProperty("java.specification.version")
+ ",hl=2"
+ ",t="
+ metaVersion
+ ",hc="
+ (httpClientVersion == null ? "" : httpClientVersion.getRelease())
+ LanguageRuntimeVersions.getRuntimeMetadata();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ public class RequestOptionsTest extends Assert {
private static HttpServer httpServer;
private static RestClient restClient;


@Before
public void classSetup() throws IOException {

Expand Down Expand Up @@ -110,6 +109,7 @@ public void testDefaultHeaders() throws IOException {

assertTrue(props.getProperty("header-user-agent").startsWith("elastic-java/" + Version.VERSION.toString()));
assertTrue(props.getProperty("header-x-elastic-client-meta").contains("es="));
assertTrue(props.getProperty("header-x-elastic-client-meta").contains("hl=2"));
assertEquals(
"application/vnd.elasticsearch+json; compatible-with=" + String.valueOf(Version.VERSION.major()),
props.getProperty("header-accept")
Expand Down

0 comments on commit a477ed0

Please sign in to comment.