Skip to content

Commit

Permalink
Added support to azure blob storage framework (elastic#1641)
Browse files Browse the repository at this point in the history
  • Loading branch information
tanquetav committed Feb 20, 2022
1 parent f40727f commit 42b6684
Show file tree
Hide file tree
Showing 16 changed files with 955 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ endif::[]
[float]
===== Features
* Added support for azure blob storage framework -
* Added support for setting service name and version for a transaction via the public api - {pull}2451[#2451]
* Added support for en-/disabling each public annotation on each own - {pull}2472[#2472]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>apm-azure-storage</artifactId>
<groupId>co.elastic.apm</groupId>
<version>1.29.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>apm-azure-storage-core-plugin</artifactId>
<name>${project.groupId}:${project.artifactId}</name>

<properties>
<apm-agent-parent.base.dir>${project.basedir}/../../..</apm-agent-parent.base.dir>
</properties>

<dependencies>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* 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.apm.agent.azurestorage;

import co.elastic.apm.agent.impl.Tracer;
import co.elastic.apm.agent.impl.transaction.AbstractSpan;
import co.elastic.apm.agent.impl.transaction.Span;

import java.net.URL;
import java.util.Map;

public class AzureStorageHelper {
private final Tracer tracer;
public static String SPAN_NAME = "AzureBlob";
public static String SPAN_SUBTYPE = "azureblob";
public static String SPAN_TYPE = "storage";

public AzureStorageHelper(Tracer tracer) {
this.tracer = tracer;
}

public Span startAzureStorageSpan(String method, URL url, Map<String, String> requestHeaderMap) {

Span span = tracer.createExitChildSpan();
if (span == null) {
return null;
}

BlobUrl blobUrl = new BlobUrl(url);
String action = null;

String query = url.getQuery() != null ? url.getQuery().toLowerCase() : "";

switch (method)
{
case "DELETE":
action = "Delete";
break;
case "GET":
if (query.indexOf("restype=container")!=-1)
{
if (query.indexOf("comp=list")!=-1)
action = "ListBlobs";
else if (query.indexOf("comp=acl")!=-1)
action = "GetAcl";
else
action = "GetProperties";
}
else
{
if (query.indexOf("comp=metadata")!=-1)
action = "GetMetadata";
else if (query.indexOf("comp=list")!=-1)
action = "ListContainers";
else if (query.indexOf("comp=tags")!=-1)
action = query.indexOf("where=")!=-1 ? "FindTags" : "GetTags";
else
action = "Download";
}
break;
case "HEAD":
if (query.indexOf("comp=metadata")!=-1)
action = "GetMetadata";
else if (query.indexOf("comp=acl")!=-1)
action = "GetAcl";
else
action = "GetProperties";
break;
case "POST":
if (query.indexOf("comp=batch")!=-1)
action = "Batch";
else if (query.indexOf("comp=query")!=-1)
action = "Query";
break;
case "PUT":
String msCopySource = requestHeaderMap.get("x-ms-copy-source");
String msBlobType = requestHeaderMap.get("x-ms-blob-type");
if (msCopySource!=null && !"".equals(msCopySource))
action = "Copy";
else if (query.indexOf("comp=copy")!=-1)
action = "Abort";
else if ((msBlobType!=null &&!"".equals(msBlobType)) ||
query.indexOf("comp=block")!=-1 ||
query.indexOf("comp=blocklist")!=-1 ||
query.indexOf("comp=page")!=-1 ||
query.indexOf("comp=appendblock")!=-1)
action = "Upload";
else if (query.indexOf("comp=metadata")!=-1)
action = "SetMetadata";
else if (query.indexOf("comp=acl")!=-1)
action = "SetAcl";
else if (query.indexOf("comp=properties")!=-1)
action = "SetProperties";
else if (query.indexOf("comp=lease")!=-1)
action = "Lease";
else if (query.indexOf("comp=snapshot")!=-1)
action = "Snapshot";
else if (query.indexOf("comp=undelete")!=-1)
action = "Undelete";
else if (query.indexOf("comp=tags")!=-1)
action = "SetTags";
else if (query.indexOf("comp=tier")!=-1)
action = "SetTier";
else if (query.indexOf("comp=expiry")!=-1)
action = "SetExpiry";
else if (query.indexOf("comp=seal")!=-1)
action = "Seal";
else
action = "Create";

break;
}

if (action == null) return null;

String name = SPAN_NAME + " " + action + " " + blobUrl.getResourceName();

span.activate()
.withAction(action)
.withType(SPAN_TYPE)
.withSubtype(SPAN_SUBTYPE)
.withName(name, AbstractSpan.PRIO_DEFAULT - 1);

span.appendToName(name);

span.getContext()
.getDestination()
.withAddress(blobUrl.getFullyQualifiedNamespace())
.withPort(blobUrl.getPort())
.getService()
.withType(SPAN_TYPE)
.withResource(SPAN_SUBTYPE + "/" + blobUrl.getStorageAccountName())
.withName(name);
return span;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* 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.apm.agent.azurestorage;

import java.net.URL;

public class BlobUrl {
private String resourceName;
private String storageAccountName;
private String fullyQualifiedNamespace;
private int port;

public BlobUrl(URL url) {
resourceName = url.getPath();
port = url.getPort();
if (port <= 0) {
port = 80;
}
String[] split = url.getHost().split("\\.");
if (split.length > 0) {
storageAccountName = split[0];
}
fullyQualifiedNamespace = url.getHost();
if ("127".equals(storageAccountName)) {
// Dev Mode (azurite) account name is not on url
// https://docs.microsoft.com/en-us/azure/storage/common/storage-configure-connection-string
String[] split1 = resourceName.split("/");
if (split1.length > 1) {
storageAccountName = split1[1];
resourceName = resourceName.substring(storageAccountName.length() + 1);
}
}
}

public String getResourceName() {
return resourceName;
}

public String getStorageAccountName() {
return storageAccountName;
}

public String getFullyQualifiedNamespace() {
return fullyQualifiedNamespace;
}

public int getPort() {
return port;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* 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.apm.agent.azurestorage;

import co.elastic.apm.agent.impl.transaction.Span;
import co.elastic.apm.agent.sdk.weakconcurrent.DetachedThreadLocal;
import co.elastic.apm.agent.sdk.weakconcurrent.WeakConcurrent;

import javax.annotation.Nullable;

public class SpanTrackerHolder {
private static DetachedThreadLocal<SpanTrackerHolder> detachedThreadLocal = WeakConcurrent.buildThreadLocal();

public static SpanTrackerHolder getSpanTrackHolder() {
SpanTrackerHolder spanTrackerHolder = detachedThreadLocal.get();
if (spanTrackerHolder == null) {
spanTrackerHolder = new SpanTrackerHolder();
detachedThreadLocal.set(spanTrackerHolder);
}
return spanTrackerHolder;
}
public static void removeSpanTrackHolder() {
detachedThreadLocal.remove();
}

public static boolean isCreated() {
return detachedThreadLocal.get() != null;
}

private SpanTrackerHolder() {
}

@Nullable
private Span span;
private boolean storageEntrypointCreated;

@Nullable
public Span getSpan() {
return span;
}

public void setSpan(Span span) {
this.span = span;
}

public boolean isStorageEntrypointCreated() {
return storageEntrypointCreated;
}

public void setStorageEntrypointCreated(boolean storageEntrypointCreated) {
this.storageEntrypointCreated = storageEntrypointCreated;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* 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.
*/
@NonnullApi
package co.elastic.apm.agent.azurestorage;

import co.elastic.apm.agent.sdk.NonnullApi;
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>apm-azure-storage</artifactId>
<groupId>co.elastic.apm</groupId>
<version>1.29.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>apm-azure-storage-plugin</artifactId>
<name>${project.groupId}:${project.artifactId}</name>

<properties>
<apm-agent-parent.base.dir>${project.basedir}/../../..</apm-agent-parent.base.dir>
<maven.compiler.target>8</maven.compiler.target>
<maven.compiler.source>${maven.compiler.target}</maven.compiler.source>
<maven.compiler.release>${maven.compiler.target}</maven.compiler.release>
<animal.sniffer.skip>true</animal.sniffer.skip>
</properties>

<dependencies>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-storage-blob</artifactId>
<version>12.14.3</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>apm-azure-storage-core-plugin</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>

</project>
Loading

0 comments on commit 42b6684

Please sign in to comment.