You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zipkin.apache.org by ad...@apache.org on 2019/06/14 09:03:07 UTC
[incubator-zipkin] branch master updated: Updates to Armeria 0.87
and addresses deprecations (#2631)
This is an automated email from the ASF dual-hosted git repository.
adriancole pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-zipkin.git
The following commit(s) were added to refs/heads/master by this push:
new fa4bee0 Updates to Armeria 0.87 and addresses deprecations (#2631)
fa4bee0 is described below
commit fa4bee068b3366be3440b15f50b4b9368917cbc2
Author: Adrian Cole <ad...@users.noreply.github.com>
AuthorDate: Fri Jun 14 17:02:54 2019 +0800
Updates to Armeria 0.87 and addresses deprecations (#2631)
---
pom.xml | 2 +-
.../collector/scribe/ScribeInboundHandler.java | 2 +-
.../server/internal/MetricsHealthController.java | 2 +-
.../internal/RegisterZipkinHealthIndicators.java | 3 +--
.../server/internal/ZipkinHealthIndicator.java | 3 +--
.../server/internal/ZipkinHttpCollector.java | 27 ++++++++++---------
.../zipkin2/server/internal/ZipkinQueryApiV2.java | 30 +++++++++++-----------
.../server/internal/ZipkinServerConfiguration.java | 8 +++---
.../internal/brave/TracingStorageComponent.java | 6 ++---
.../ZipkinPrometheusMetricsConfiguration.java | 5 ++--
.../server/internal/ui/ZipkinUiConfiguration.java | 10 ++++----
.../internal/ui/ZipkinUiConfigurationTest.kt | 4 +--
12 files changed, 49 insertions(+), 53 deletions(-)
diff --git a/pom.xml b/pom.xml
index 73fe369..dbc5acb 100755
--- a/pom.xml
+++ b/pom.xml
@@ -48,7 +48,7 @@
<main.basedir>${project.basedir}</main.basedir>
- <armeria.version>0.86.0</armeria.version>
+ <armeria.version>0.87.0</armeria.version>
<!-- This is from armeria, but be careful to avoid >= v20 apis -->
<guava.version>27.1-jre</guava.version>
diff --git a/zipkin-collector/scribe/src/main/java/zipkin2/collector/scribe/ScribeInboundHandler.java b/zipkin-collector/scribe/src/main/java/zipkin2/collector/scribe/ScribeInboundHandler.java
index 342ec56..5594211 100644
--- a/zipkin-collector/scribe/src/main/java/zipkin2/collector/scribe/ScribeInboundHandler.java
+++ b/zipkin-collector/scribe/src/main/java/zipkin2/collector/scribe/ScribeInboundHandler.java
@@ -162,7 +162,7 @@ final class ScribeInboundHandler extends ChannelInboundHandlerAdapter {
buf.release();
}
} else {
- returned.writeBytes(content.array(), content.offset(), content.length());
+ returned.writeBytes(content.array());
}
if (responseIndex == previouslySentResponseIndex + 1) {
diff --git a/zipkin-server/src/main/java/zipkin2/server/internal/MetricsHealthController.java b/zipkin-server/src/main/java/zipkin2/server/internal/MetricsHealthController.java
index 1906b47..6bdce4f 100644
--- a/zipkin-server/src/main/java/zipkin2/server/internal/MetricsHealthController.java
+++ b/zipkin-server/src/main/java/zipkin2/server/internal/MetricsHealthController.java
@@ -96,6 +96,6 @@ public class MetricsHealthController {
ResponseHeaders headers = ResponseHeaders.builder(statusMapper.mapStatus(health.getStatus()))
.contentType(MediaType.JSON)
.setInt(HttpHeaderNames.CONTENT_LENGTH, body.length).build();
- return HttpResponse.of(headers, HttpData.of(body));
+ return HttpResponse.of(headers, HttpData.wrap(body));
}
}
diff --git a/zipkin-server/src/main/java/zipkin2/server/internal/RegisterZipkinHealthIndicators.java b/zipkin-server/src/main/java/zipkin2/server/internal/RegisterZipkinHealthIndicators.java
index 8bc96f3..a6b473d 100644
--- a/zipkin-server/src/main/java/zipkin2/server/internal/RegisterZipkinHealthIndicators.java
+++ b/zipkin-server/src/main/java/zipkin2/server/internal/RegisterZipkinHealthIndicators.java
@@ -23,8 +23,7 @@ import zipkin2.Component;
// This is an application listener to ensure the graph is fully constructed before doing health
public final class RegisterZipkinHealthIndicators implements ApplicationListener {
- @Override
- public void onApplicationEvent(ApplicationEvent event) {
+ @Override public void onApplicationEvent(ApplicationEvent event) {
if (!(event instanceof ApplicationReadyEvent)) return;
ConfigurableListableBeanFactory beanFactory =
((ApplicationReadyEvent) event).getApplicationContext().getBeanFactory();
diff --git a/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinHealthIndicator.java b/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinHealthIndicator.java
index 9a1569d..aabd737 100644
--- a/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinHealthIndicator.java
+++ b/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinHealthIndicator.java
@@ -40,8 +40,7 @@ final class ZipkinHealthIndicator extends CompositeHealthIndicator {
}
/** synchronized to prevent overlapping requests to a storage backend */
- @Override
- public synchronized Health health() {
+ @Override public synchronized Health health() {
CheckResult result = component.check();
return result.ok() ? Health.up().build() : Health.down((Exception) result.error()).build();
}
diff --git a/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinHttpCollector.java b/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinHttpCollector.java
index d538d16..09d204a 100644
--- a/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinHttpCollector.java
+++ b/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinHttpCollector.java
@@ -14,7 +14,7 @@
package zipkin2.server.internal;
import com.linecorp.armeria.client.encoding.GzipStreamDecoderFactory;
-import com.linecorp.armeria.common.AggregatedHttpMessage;
+import com.linecorp.armeria.common.AggregatedHttpRequest;
import com.linecorp.armeria.common.HttpData;
import com.linecorp.armeria.common.HttpHeaderNames;
import com.linecorp.armeria.common.HttpRequest;
@@ -115,15 +115,15 @@ public class ZipkinHttpCollector {
return null;
}
+ final HttpData content;
try {
- final HttpData content;
- try {
- content = UnzippingBytesRequestConverter.convertRequest(ctx, msg);
- } catch (IllegalArgumentException e) {
- result.onError(e);
- return null;
- }
+ content = UnzippingBytesRequestConverter.convertRequest(ctx, msg);
+ } catch (IllegalArgumentException e) {
+ result.onError(e);
+ return null;
+ }
+ try {
// logging already handled upstream in UnzippingBytesRequestConverter where request context exists
if (content.isEmpty()) {
result.onSuccess(null);
@@ -134,9 +134,7 @@ public class ZipkinHttpCollector {
if (content instanceof ByteBufHolder) {
nioBuffer = ((ByteBufHolder) content).content().nioBuffer();
} else {
- // Currently this will happen for gzip spans. Need to fix armeria's gzip decoder to allow
- // returning pooled buffers on request.
- nioBuffer = ByteBuffer.wrap(content.array(), content.offset(), content.length());
+ nioBuffer = ByteBuffer.wrap(content.array());
}
try {
@@ -161,7 +159,7 @@ public class ZipkinHttpCollector {
// UnzippingBytesRequestConverter handles incrementing message and bytes
collector.accept(spans, result);
} finally {
- ReferenceCountUtil.release(msg.content());
+ ReferenceCountUtil.release(content);
}
return null;
@@ -170,7 +168,7 @@ public class ZipkinHttpCollector {
return HttpResponse.from(result);
}
- static void maybeLog(String prefix, ServiceRequestContext ctx, AggregatedHttpMessage request) {
+ static void maybeLog(String prefix, ServiceRequestContext ctx, AggregatedHttpRequest request) {
if (!LOGGER.isDebugEnabled()) return;
LOGGER.debug("{} sent by clientAddress->{}, userAgent->{}",
prefix, ctx.clientAddress(), request.headers().get(HttpHeaderNames.USER_AGENT)
@@ -205,7 +203,7 @@ final class CompletableCallback extends CompletableFuture<HttpResponse>
final class UnzippingBytesRequestConverter {
static final GzipStreamDecoderFactory GZIP_DECODER_FACTORY = new GzipStreamDecoderFactory();
- static HttpData convertRequest(ServiceRequestContext ctx, AggregatedHttpMessage request) {
+ static HttpData convertRequest(ServiceRequestContext ctx, AggregatedHttpRequest request) {
ZipkinHttpCollector.metrics.incrementMessages();
String encoding = request.headers().get(HttpHeaderNames.CONTENT_ENCODING);
HttpData content = request.content();
@@ -214,6 +212,7 @@ final class UnzippingBytesRequestConverter {
// The implementation of the armeria decoder is to return an empty body on failure
if (content.isEmpty()) {
ZipkinHttpCollector.maybeLog("Malformed gzip body", ctx, request);
+ ReferenceCountUtil.release(content);
throw new IllegalArgumentException("Cannot gunzip spans");
}
}
diff --git a/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinQueryApiV2.java b/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinQueryApiV2.java
index 4cd0b47..4f7c2b6 100644
--- a/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinQueryApiV2.java
+++ b/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinQueryApiV2.java
@@ -13,7 +13,7 @@
*/
package zipkin2.server.internal;
-import com.linecorp.armeria.common.AggregatedHttpMessage;
+import com.linecorp.armeria.common.AggregatedHttpResponse;
import com.linecorp.armeria.common.HttpData;
import com.linecorp.armeria.common.HttpHeaderNames;
import com.linecorp.armeria.common.HttpStatus;
@@ -70,7 +70,7 @@ public class ZipkinQueryApiV2 {
}
@Get("/api/v2/dependencies")
- public AggregatedHttpMessage getDependencies(
+ public AggregatedHttpResponse getDependencies(
@Param("endTs") long endTs,
@Param("lookback") Optional<Long> lookback) throws IOException {
Call<List<DependencyLink>> call =
@@ -79,20 +79,20 @@ public class ZipkinQueryApiV2 {
}
@Get("/api/v2/services")
- public AggregatedHttpMessage getServiceNames() throws IOException {
+ public AggregatedHttpResponse getServiceNames() throws IOException {
List<String> serviceNames = storage.serviceAndSpanNames().getServiceNames().execute();
serviceCount = serviceNames.size();
return maybeCacheNames(serviceCount > 3, serviceNames);
}
@Get("/api/v2/spans")
- public AggregatedHttpMessage getSpanNames(@Param("serviceName") String serviceName) throws IOException {
+ public AggregatedHttpResponse getSpanNames(@Param("serviceName") String serviceName) throws IOException {
List<String> spanNames = storage.serviceAndSpanNames().getSpanNames(serviceName).execute();
return maybeCacheNames(serviceCount > 3, spanNames);
}
@Get("/api/v2/remoteServices")
- public AggregatedHttpMessage getRemoteServiceNames(@Param("serviceName") String serviceName)
+ public AggregatedHttpResponse getRemoteServiceNames(@Param("serviceName") String serviceName)
throws IOException {
List<String> remoteServiceNames =
storage.serviceAndSpanNames().getRemoteServiceNames(serviceName).execute();
@@ -100,7 +100,7 @@ public class ZipkinQueryApiV2 {
}
@Get("/api/v2/traces")
- public AggregatedHttpMessage getTraces(
+ public AggregatedHttpResponse getTraces(
@Param("serviceName") Optional<String> serviceName,
@Param("remoteServiceName") Optional<String> remoteServiceName,
@Param("spanName") Optional<String> spanName,
@@ -129,19 +129,19 @@ public class ZipkinQueryApiV2 {
}
@Get("/api/v2/trace/{traceIdHex}")
- public AggregatedHttpMessage getTrace(@Param("traceIdHex") String traceIdHex) throws IOException {
+ public AggregatedHttpResponse getTrace(@Param("traceIdHex") String traceIdHex) throws IOException {
List<Span> trace = storage.spanStore().getTrace(traceIdHex).execute();
if (trace == null) {
- return AggregatedHttpMessage.of(HttpStatus.NOT_FOUND, MediaType.PLAIN_TEXT_UTF_8,
+ return AggregatedHttpResponse.of(HttpStatus.NOT_FOUND, MediaType.PLAIN_TEXT_UTF_8,
traceIdHex + " not found");
}
return jsonResponse(SpanBytesEncoder.JSON_V2.encodeList(trace));
}
- static AggregatedHttpMessage jsonResponse(byte[] body) {
- return AggregatedHttpMessage.of(ResponseHeaders.builder(200)
+ static AggregatedHttpResponse jsonResponse(byte[] body) {
+ return AggregatedHttpResponse.of(ResponseHeaders.builder(200)
.contentType(MediaType.JSON)
- .setInt(HttpHeaderNames.CONTENT_LENGTH, body.length).build(), HttpData.of(body));
+ .setInt(HttpHeaderNames.CONTENT_LENGTH, body.length).build(), HttpData.wrap(body));
}
static final WriteBuffer.Writer<String> QUOTED_STRING_WRITER = new WriteBuffer.Writer<String>() {
@@ -157,12 +157,12 @@ public class ZipkinQueryApiV2 {
};
@Get("/api/v2/autocompleteKeys")
- public AggregatedHttpMessage getAutocompleteKeys() {
+ public AggregatedHttpResponse getAutocompleteKeys() {
return maybeCacheNames(true, autocompleteKeys);
}
@Get("/api/v2/autocompleteValues")
- public AggregatedHttpMessage getAutocompleteValues(@Param("key") String key) throws IOException {
+ public AggregatedHttpResponse getAutocompleteValues(@Param("key") String key) throws IOException {
List<String> values = storage.autocompleteTags().getValues(key).execute();
return maybeCacheNames(values.size() > 3, values);
}
@@ -172,7 +172,7 @@ public class ZipkinQueryApiV2 {
* empty results, users have more questions. We assume caching becomes a concern when zipkin is in
* active use, and active use usually implies more than 3 services.
*/
- AggregatedHttpMessage maybeCacheNames(boolean shouldCacheControl, List<String> values) {
+ AggregatedHttpResponse maybeCacheNames(boolean shouldCacheControl, List<String> values) {
Collections.sort(values);
byte[] body = JsonCodec.writeList(QUOTED_STRING_WRITER, values);
ResponseHeadersBuilder headers = ResponseHeaders.builder(200)
@@ -184,7 +184,7 @@ public class ZipkinQueryApiV2 {
CacheControl.maxAge(namesMaxAge, TimeUnit.SECONDS).mustRevalidate().getHeaderValue()
);
}
- return AggregatedHttpMessage.of(headers.build(), HttpData.of(body));
+ return AggregatedHttpResponse.of(headers.build(), HttpData.wrap(body));
}
// This is inlined here as there isn't enough re-use to warrant it being in the zipkin2 library
diff --git a/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinServerConfiguration.java b/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinServerConfiguration.java
index fe236fe..9ec10b8 100644
--- a/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinServerConfiguration.java
+++ b/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinServerConfiguration.java
@@ -31,6 +31,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.boot.actuate.health.HealthAggregator;
+import org.springframework.boot.actuate.health.HealthIndicatorRegistry;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -44,13 +45,13 @@ import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-import zipkin2.server.internal.throttle.ZipkinStorageThrottleProperties;
import zipkin2.collector.CollectorMetrics;
import zipkin2.collector.CollectorSampler;
import zipkin2.server.internal.brave.TracingStorageComponent;
+import zipkin2.server.internal.throttle.ThrottledStorageComponent;
+import zipkin2.server.internal.throttle.ZipkinStorageThrottleProperties;
import zipkin2.storage.InMemoryStorage;
import zipkin2.storage.StorageComponent;
-import zipkin2.server.internal.throttle.ThrottledStorageComponent;
@Configuration
@ImportAutoConfiguration(ArmeriaSpringActuatorAutoConfiguration.class)
@@ -86,8 +87,7 @@ public class ZipkinServerConfiguration implements WebMvcConfigurer {
return new ZipkinHealthIndicator(healthAggregator);
}
- @Override
- public void addViewControllers(ViewControllerRegistry registry) {
+ @Override public void addViewControllers(ViewControllerRegistry registry) {
registry.addRedirectViewController("/info", "/actuator/info");
}
diff --git a/zipkin-server/src/main/java/zipkin2/server/internal/brave/TracingStorageComponent.java b/zipkin-server/src/main/java/zipkin2/server/internal/brave/TracingStorageComponent.java
index 81b4b63..b736f18 100644
--- a/zipkin-server/src/main/java/zipkin2/server/internal/brave/TracingStorageComponent.java
+++ b/zipkin-server/src/main/java/zipkin2/server/internal/brave/TracingStorageComponent.java
@@ -73,13 +73,11 @@ public final class TracingStorageComponent extends StorageComponent {
return new TracedCall<>(tracer, delegate.getTrace(traceId), "get-trace");
}
- @Override
- public Call<List<String>> getServiceNames() {
+ @Override @Deprecated public Call<List<String>> getServiceNames() {
return new TracedCall<>(tracer, delegate.getServiceNames(), "get-service-names");
}
- @Override
- public Call<List<String>> getSpanNames(String serviceName) {
+ @Override @Deprecated public Call<List<String>> getSpanNames(String serviceName) {
return new TracedCall<>(tracer, delegate.getSpanNames(serviceName), "get-span-names");
}
diff --git a/zipkin-server/src/main/java/zipkin2/server/internal/prometheus/ZipkinPrometheusMetricsConfiguration.java b/zipkin-server/src/main/java/zipkin2/server/internal/prometheus/ZipkinPrometheusMetricsConfiguration.java
index 7356870..aa44951 100644
--- a/zipkin-server/src/main/java/zipkin2/server/internal/prometheus/ZipkinPrometheusMetricsConfiguration.java
+++ b/zipkin-server/src/main/java/zipkin2/server/internal/prometheus/ZipkinPrometheusMetricsConfiguration.java
@@ -20,7 +20,7 @@ import com.linecorp.armeria.common.RequestContext;
import com.linecorp.armeria.common.Response;
import com.linecorp.armeria.common.logging.RequestLog;
import com.linecorp.armeria.common.logging.RequestLogAvailability;
-import com.linecorp.armeria.server.PathMapping;
+import com.linecorp.armeria.server.Route;
import com.linecorp.armeria.server.Service;
import com.linecorp.armeria.server.ServiceRequestContext;
import com.linecorp.armeria.server.SimpleDecoratingService;
@@ -73,7 +73,8 @@ public class ZipkinPrometheusMetricsConfiguration {
@Order(1)
ArmeriaServerConfigurator notFoundMetricCollector() {
// Use glob instead of catch-all to avoid adding it to the trie router.
- return sb -> sb.service(PathMapping.ofGlob("/**"), (ctx, req) -> HttpResponse.of(HttpStatus.NOT_FOUND));
+ return sb -> sb.service(Route.builder().glob("/**").build(),
+ (ctx, req) -> HttpResponse.of(HttpStatus.NOT_FOUND));
}
static final class MetricCollectingService<I extends Request, O extends Response>
diff --git a/zipkin-server/src/main/java/zipkin2/server/internal/ui/ZipkinUiConfiguration.java b/zipkin-server/src/main/java/zipkin2/server/internal/ui/ZipkinUiConfiguration.java
index 28f01aa..f507467 100644
--- a/zipkin-server/src/main/java/zipkin2/server/internal/ui/ZipkinUiConfiguration.java
+++ b/zipkin-server/src/main/java/zipkin2/server/internal/ui/ZipkinUiConfiguration.java
@@ -21,11 +21,11 @@ import com.linecorp.armeria.common.HttpRequest;
import com.linecorp.armeria.common.HttpResponse;
import com.linecorp.armeria.common.HttpStatus;
import com.linecorp.armeria.common.MediaType;
+import com.linecorp.armeria.common.ServerCacheControl;
+import com.linecorp.armeria.common.ServerCacheControlBuilder;
import com.linecorp.armeria.server.AbstractHttpService;
import com.linecorp.armeria.server.HttpService;
import com.linecorp.armeria.server.RedirectService;
-import com.linecorp.armeria.server.ServerCacheControl;
-import com.linecorp.armeria.server.ServerCacheControlBuilder;
import com.linecorp.armeria.server.Service;
import com.linecorp.armeria.server.ServiceRequestContext;
import com.linecorp.armeria.server.encoding.HttpEncodingService;
@@ -126,8 +126,8 @@ public class ZipkinUiConfiguration {
legacyIndex = HttpFileBuilder.ofResource("zipkin-ui/index.html");
lensIndex = HttpFileBuilder.ofResource("zipkin-lens/index.html");
} else {
- legacyIndex = HttpFileBuilder.of(HttpData.of(processedIndexHtml().getBytes(UTF_8)));
- lensIndex = HttpFileBuilder.of(HttpData.of(processedLensIndexHtml().getBytes(UTF_8)));
+ legacyIndex = HttpFileBuilder.of(HttpData.wrap(processedIndexHtml().getBytes(UTF_8)));
+ lensIndex = HttpFileBuilder.of(HttpData.wrap(processedLensIndexHtml().getBytes(UTF_8)));
}
ServerCacheControl maxAgeMinute = new ServerCacheControlBuilder().maxAgeSeconds(60).build();
@@ -153,7 +153,7 @@ public class ZipkinUiConfiguration {
byte[] config = new ObjectMapper().writeValueAsBytes(ui);
return sb -> {
- sb.service("/zipkin/config.json", HttpFileBuilder.of(HttpData.of(config))
+ sb.service("/zipkin/config.json", HttpFileBuilder.of(HttpData.wrap(config))
.cacheControl(new ServerCacheControlBuilder().maxAgeSeconds(600).build())
.contentType(MediaType.JSON_UTF_8)
.build()
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/ui/ZipkinUiConfigurationTest.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ui/ZipkinUiConfigurationTest.kt
index 3171d40..18cf8f5 100644
--- a/zipkin-server/src/test/kotlin/zipkin2/server/internal/ui/ZipkinUiConfigurationTest.kt
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ui/ZipkinUiConfigurationTest.kt
@@ -13,7 +13,7 @@
*/
package zipkin2.server.internal.ui
-import com.linecorp.armeria.common.AggregatedHttpMessage
+import com.linecorp.armeria.common.AggregatedHttpResponse
import com.linecorp.armeria.common.HttpHeaderNames
import com.linecorp.armeria.common.HttpMethod
import com.linecorp.armeria.common.HttpRequest
@@ -160,7 +160,7 @@ class ZipkinUiConfigurationTest {
.contains("<base href=\"/\">")
}
- private fun serveIndex(vararg cookies: Cookie): AggregatedHttpMessage {
+ private fun serveIndex(vararg cookies: Cookie): AggregatedHttpResponse {
val headers = RequestHeaders.builder(HttpMethod.GET, "/")
val encodedCookies = ClientCookieEncoder.LAX.encode(*cookies)
if (encodedCookies != null) {