Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into feature/integration-t…
Browse files Browse the repository at this point in the history
…ests
  • Loading branch information
Mpdreamz committed Feb 13, 2024
2 parents 9e656b1 + 592036b commit d70e7d7
Show file tree
Hide file tree
Showing 28 changed files with 1,301 additions and 155 deletions.
33 changes: 33 additions & 0 deletions .github/workflows/ci-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# This workflow sets the 'test-windows' and 'builds' status check to success in case it's a docs only PR and ci.yml is not triggered
# https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/troubleshooting-required-status-checks#handling-skipped-but-required-checks
name: Pull Request Validation # The name must be the same as in ci.yml

on:
pull_request:
paths-ignore: # This expression needs to match the paths ignored on ci.yml.
- '**'
- '!*.md'
- '!*.asciidoc'
- '!docs/**'

permissions:
contents: read

## Concurrency only allowed in the main branch.
## So old builds running for old commits within the same Pull Request are cancelled
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

jobs:
# dummy steps that allow to bypass those mandatory checks for tests
test-windows:
runs-on: ubuntu-latest
steps:
- run: 'echo "Not required for docs"'

# dummy steps that allow to bypass those mandatory checks for tests
build:
runs-on: ubuntu-latest
steps:
- run: 'echo "Not required for docs"'
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ concurrency:
env:
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages

# NOTE: if you add a new job and it's a mandatory check then
# update ci.yml
jobs:
test-windows:
runs-on: windows-latest
Expand Down
27 changes: 27 additions & 0 deletions .github/workflows/e2e-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# This workflow sets the 'test' status check to success in case it's a docs only PR and e2e.yml is not triggered
# https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/troubleshooting-required-status-checks#handling-skipped-but-required-checks
name: e2e # The name must be the same as in e2e.yml

on:
pull_request:
paths-ignore: # This expression needs to match the paths ignored on e2e.yml.
- '**'
- '!*.md'
- '!*.asciidoc'
- '!docs/**'

permissions:
contents: read

## Concurrency only allowed in the main branch.
## So old builds running for old commits within the same Pull Request are cancelled
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

jobs:
# dummy steps that allow to bypass those mandatory checks for tests
test:
runs-on: ubuntu-latest
steps:
- run: 'echo "Not required for docs"'
20 changes: 16 additions & 4 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,13 @@ concurrency:
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

env:
# keep_serverless-staging-oblt OR keep_serverless-qa-oblt
# (keep_serverless-staging-oblt, keep_serverless-qa-oblt or serverless-production-oblt)
SERVERLESS_PROJECT: serverless-production-oblt
# (staging, qa or production)
VAULT_SECRET_SUFFIX: production

# NOTE: if you add a new job and it's a mandatory check then
# update e2e-docs.yml
jobs:
test:
if: |
Expand All @@ -51,10 +55,18 @@ jobs:
vault-role-id: ${{ secrets.VAULT_ROLE_ID }}
vault-secret-id: ${{ secrets.VAULT_SECRET_ID }}

- name: Get the browser email and password from Vault
uses: hashicorp/[email protected]
with:
url: ${{ secrets.VAULT_ADDR }}
roleId: ${{ secrets.VAULT_ROLE_ID }}
secretId: ${{ secrets.VAULT_SECRET_ID }}
method: approle
secrets: |
secret/observability-team/ci/elastic-cloud/observability-team-${{ env.VAULT_SECRET_SUFFIX }} username | E2E__BROWSEREMAIL
secret/observability-team/ci/elastic-cloud/observability-team-${{ env.VAULT_SECRET_SUFFIX }} password | E2E__BROWSERPASSWORD
- run: ./build.sh test --test-suite=e2e
env:
E2E__ENDPOINT: "${{env.ELASTIC_APM_SERVER_URL}}"
E2E__AUTHORIZATION: "Authentication=ApiKey ${{env.ELASTIC_APM_API_KEY}}"
E2E__BROWSEREMAIL: "${{env.KIBANA_USERNAME}}"
E2E__BROWSERPASSWORD: "${{env.KIBANA_PASSWORD}}"
E2E__AUTHORIZATION: "Authentication=ApiKey ${{env.ELASTIC_APM_API_KEY}}"
1 change: 1 addition & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<UseArtifactsOutput>true</UseArtifactsOutput>
<SolutionRoot>$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), build.bat))</SolutionRoot>
<ArtifactsPath>$(MSBuildThisFileDirectory).artifacts</ArtifactsPath>
<ExposedPublicKey>002400000480000094000000060200000024000052534131000400000100010015b0fa59d868c7f3ea2ae67567b19e102465745f01b430a38a42b92fd41a0f5869bec1f2b33b589d78662af432fe6b789ef72d4738f7b1a86264d7aeb5185ed8995b2bb104e7c5c58845f1a618be829e410fa34a6bd7d714ece191ed68a66333a83ae7456ee32e9aeb54bc1d7410ae8c344367257e9001abb5e96ce1f1d97696</ExposedPublicKey>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MinVer" Version="4.3.0" PrivateAssets="all" />
Expand Down
5 changes: 3 additions & 2 deletions examples/Example.Elastic.OpenTelemetry.Worker/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
using Example.Elastic.OpenTelemetry.Worker;

var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<Worker>();

builder.Services.AddElasticOpenTelemetry("CustomActivitySource");
builder.EnableElasticOpenTelemetry("CustomActivitySource");

builder.Services.AddHostedService<Worker>();

var host = builder.Build();
host.Run();
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting.Lifetime": "Information"
"Microsoft.Hosting.Lifetime": "Information",
"Elastic": "Trace"
}
}
}
218 changes: 133 additions & 85 deletions src/Elastic.OpenTelemetry/Agent.cs
Original file line number Diff line number Diff line change
@@ -1,97 +1,145 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
using OpenTelemetry;
using System.Reflection;
using Microsoft.Extensions.Logging;

using static Elastic.OpenTelemetry.Diagnostics.ElasticOpenTelemetryDiagnosticSource;

namespace Elastic.OpenTelemetry;

/// <summary>
/// Supports building and accessing an <see cref="IAgent"/> which collects and ships observability signals.
/// </summary>
public static class Agent
public static partial class Agent
{
private static readonly object Lock = new();
private static IAgent? _current;

static Agent()
{
var assemblyInformationalVersion = typeof(Agent).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;
InformationalVersion = ParseAssemblyInformationalVersion(assemblyInformationalVersion);
}

/// <summary>
/// Returns the singleton <see cref="IAgent"/> instance.
/// </summary>
/// <remarks>
/// If an instance is not already initialized, this will create and return a
/// default <see cref="IAgent"/> configured with recommended Elastic defaults.
/// </remarks>
public static IAgent Current
{
get
{
if (_current is not null) return _current;

lock (Lock)
{
// disable to satisfy double check lock pattern analyzer
// ReSharper disable once InvertIf
if (_current is null)
{
var agent = new AgentBuilder().Build();
_current = agent;
}
return _current;
}
}
}

internal static string InformationalVersion { get; }

/// <summary>
/// Builds an <see cref="IAgent"/>.
/// </summary>
/// <returns>An <see cref="IAgent"/> instance.</returns>
/// <exception cref="Exception">
/// An exception will be thrown if <see cref="Build"/>
/// is called more than once during the lifetime of an application.
/// </exception>
public static IAgent Build(Action<AgentBuilder>? configuration = null)
{
if (_current != null)
throw new Exception($"{nameof(Agent)}.{nameof(Build)} called twice or after {nameof(Agent)}.{nameof(Current)} was accessed.");

lock (Lock)
{
if (_current != null)
throw new Exception($"{nameof(Agent)}.{nameof(Build)} called twice or after {nameof(Agent)}.{nameof(Current)} was accessed.");

var agentBuilder = new AgentBuilder();
configuration?.Invoke(agentBuilder);
var agent = agentBuilder.Build();
_current = agent;
return _current;
}
}

internal static string ParseAssemblyInformationalVersion(string? informationalVersion)
{
if (string.IsNullOrWhiteSpace(informationalVersion))
{
informationalVersion = "1.0.0";
}

/*
* InformationalVersion will be in the following format:
* {majorVersion}.{minorVersion}.{patchVersion}.{pre-release label}.{pre-release version}.{gitHeight}+{Git SHA of current commit}
* Ex: 1.5.0-alpha.1.40+807f703e1b4d9874a92bd86d9f2d4ebe5b5d52e4
* The following parts are optional: pre-release label, pre-release version, git height, Git SHA of current commit
*/

var indexOfPlusSign = informationalVersion!.IndexOf('+');
return indexOfPlusSign > 0
? informationalVersion[..indexOfPlusSign]
: informationalVersion;
}
private static readonly object Lock = new();
private static IAgent? CurrentAgent;

static Agent()
{
var assemblyInformationalVersion = typeof(Agent).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;
InformationalVersion = ParseAssemblyInformationalVersion(assemblyInformationalVersion);
}

/// <summary>
/// Returns the singleton <see cref="IAgent"/> instance.
/// </summary>
/// <remarks>
/// If an instance is not already initialized, this will create and return a
/// default <see cref="IAgent"/> configured with recommended Elastic defaults.
/// </remarks>
public static IAgent Current
{
get
{
if (CurrentAgent is not null)
return CurrentAgent;

lock (Lock)
{
// disable to satisfy double check lock pattern analyzer
// ReSharper disable once InvertIf
if (CurrentAgent is null)
{
var agent = new AgentBuilder().Build();
CurrentAgent = agent;
}
return CurrentAgent;
}
}
}

internal static string InformationalVersion { get; }

/// <summary>
/// Builds an <see cref="IAgent"/>.
/// </summary>
/// <returns>An <see cref="IAgent"/> instance.</returns>
/// <exception cref="Exception">
/// An exception will be thrown if <see cref="Build"/>
/// is called more than once during the lifetime of an application.
/// </exception>
public static IAgent Build(Action<AgentBuilder>? configuration = null)
{
CheckCurrent();

lock (Lock)
{
CheckCurrent();
var agentBuilder = new AgentBuilder();
configuration?.Invoke(agentBuilder);
var agent = agentBuilder.Build();
CurrentAgent = agent;
return CurrentAgent;
}

static void CheckCurrent()
{
if (CurrentAgent is not null)
{
Log(AgentBuildCalledMultipleTimesEvent);
throw new Exception();
}
}
}

internal const string BuildErrorMessage = $"{nameof(Agent)}.{nameof(Build)} called twice or after " +
$"{nameof(Agent)}.{nameof(Current)} was accessed.";

internal const string SetAgentErrorMessage = $"{nameof(Agent)}.{nameof(SetAgent)} called twice" +
$"or after {nameof(Agent)}.{nameof(Build)} or after {nameof(Agent)}.{nameof(Current)} was accessed.";

[LoggerMessage(EventId = 1, Level = LogLevel.Error, Message = SetAgentErrorMessage)]
internal static partial void SetAgentError(this ILogger logger);

/// <summary>
/// TODO
/// </summary>
/// <param name="agent"></param>
/// <param name="logger"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
internal static IAgent SetAgent(IAgent agent, ILogger logger)
{
CheckCurrent(logger);

lock (Lock)
{
CheckCurrent(logger);
logger.LogInformation($"Setting {nameof(CurrentAgent)}.");
CurrentAgent = agent;
return CurrentAgent;
}

static void CheckCurrent(ILogger logger)
{
if (CurrentAgent is not null)
{
Log(AgentSetAgentCalledMultipleTimesEvent);
logger.SetAgentError();
throw new Exception(SetAgentErrorMessage);
}
}
}

internal static string ParseAssemblyInformationalVersion(string? informationalVersion)
{
if (string.IsNullOrWhiteSpace(informationalVersion))
{
informationalVersion = "1.0.0";
}

/*
* InformationalVersion will be in the following format:
* {majorVersion}.{minorVersion}.{patchVersion}.{pre-release label}.{pre-release version}.{gitHeight}+{Git SHA of current commit}
* Ex: 1.5.0-alpha.1.40+807f703e1b4d9874a92bd86d9f2d4ebe5b5d52e4
* The following parts are optional: pre-release label, pre-release version, git height, Git SHA of current commit
*/

var indexOfPlusSign = informationalVersion!.IndexOf('+');
return indexOfPlusSign > 0
? informationalVersion[..indexOfPlusSign]
: informationalVersion;
}
}
Loading

0 comments on commit d70e7d7

Please sign in to comment.