.NET 또는 .NET Core 추적 SDK

Instana 의 추적 기능은 자동으로 수행되지만, 사용자 정의 코드, 특정 애플리케이션 영역 또는 사내 개발 컴포넌트에 대한 더 자세한 정보를 원하신다면, Instana 의 .NET 또는 .NET Core 추적 SDK를 사용할 수 있습니다.

SDK 설치

Instana .NET 또는 .NET Core 용 SDK를 nuget.org 의 공식 피드에서 NuGet 패키지로 제공합니다. Instana.Tracing.Core.Sdk 를 검색하여 찾아 프로젝트에 추가하십시오.

자신이 작성한 코드 추적하기

다음 예제는 분산 추적 기능을 코드에 추가하는 방법을 보여줍니다.

참고: SDK는 현재 활발히 개발 중이므로, 업데이트할 때마다 이 페이지를 확인하여 최신 API를 사용하고 있는지 확인하시기 바랍니다.

간단한 span 요소 만들기

메서드 호출을 추적하는 가장 간단한 방법은 ` CustomSpan.CreateAPI `를 사용하는 것입니다.

public void MyTracedMethod()
{
    using(var span = CustomSpan.Create())
    {
        // your original code here
    }
}
 

앞의 코드는 중간 범위를 작성하여 메소드 및 메소드 내에서 소요된 시간을 표시합니다.

중간 범위를 사용하는 대신 시작 또는 종료 범위를 작성하려는 경우 편리한 API (시작 범위의 경우 CustomSpan.CreateEntry , 종료 범위의 경우 CustomSpan.CreateExit 라고 함) 를 사용할 수 있습니다.

간단한 span을 생성하고 예외를 처리하세요

메서드 본문 처리 과정에서 발생한 오류를 생성된 스팬에 주석으로 추가하려면, 다음과 같이 ` CustomSpan.SetErrorAPI `를 사용하여 수동으로 처리할 수 있습니다:

public void MyTracedMethod()
{
    using(var span = CustomSpan.Create())
    {
        try
        {
        // your original code here
        }
        catch(Exception e)
        {
            span.SetError(e.ToString());
        }
    }
}
 

더 단순하고 선호되는 방법은 CustomSpan.WrapAction 또는 CustomSpan.Wrap<T> API를 대신 사용하는 것입니다.

public void MyTracedMethod()
{
    using(var span = CustomSpan.Create())
    {
        // setting the second argument to "false" will prevent exceptions from being thrown. Instead they will be
        // captured in the span and swallowed. Setting it to true will let you handle exceptions yourself.
        span.WrapAction(
            ()=>{
                // your original code here
            }, true);
    }
}
 

포장하려는 코드 블록이 후속 처리에 필요한 결과를 반환하는 경우, 대신 CustomSpan.Wrap<T>API 를 사용하십시오.

public void MyTracedMethod()
{
    using(var span = CustomSpan.Create())
    {
        // setting the second argument to "false" will prevent exceptions from being thrown. Instead they will be
        // captured in the span and swallowed. Setting it to true will let you handle exceptions yourself.
        bool result = span.Wrap<bool>(
            ()=>{
                // your original code here
                return myBooleanValue;
            }, true);
    }
}
 

이제 항목, 엑시트 및 중간을 작성하는 방법을 알 수 있습니다. 또한 SetError 또는 WrapAction (또는 Wrap<T>) API를 사용하여 예외를 캡처하는 방법을 학습했습니다.

스팬에 데이터 추가하기

스팬 자체는 단지 타이밍, 호출 스택 및 이름으로 구성됩니다. 대부분의 시나리오에서는 그다지 유용하지 않습니다. 따라서 범위에 일부 데이터를 추가해야 합니다. 범위에는 DataTags가 포함될 수 있으며, 여기서 CustomSpan 클래스는 단순 API를 제공합니다.

public void MyTracedMethod(string userName, string someSuperRelevantData)
{
    using(var span = CustomSpan.Create())
    {
        span.SetData("username", userName);
        span.SetData("relevant", someSuperRelevantData);
        span.WrapAction(
            ()=>{
                // your original code here
            }, true);
    }
}
 

데이터가 Instana 백엔드로 전송 중이며, Instana UI에서 트레이스를 다운로드하여 확인할 수 있습니다. 하지만 여기에 표시된 데이터는 Instana UI에는 표시되지 않습니다.

span 요소에 태그 추가하기

SetData를 사용하는 대신, 문자열 배열을 키로 사용하는 SetTag를 사용할 수도 있습니다. 이 키는 범위에 전달하는 데이터를 계층 구조로 구성하는 데 사용할 수 있습니다.

public void MyTracedMethod(string userName, string someSuperRelevantData)
{
    using(var span = CustomSpan.Create())
    {
        span.SetTag("username", userName);
        span.SetTag("relevant", someSuperRelevantData);
        span.WrapAction(
            ()=>{
                // your original code here
            }, true);
    }
}
 

태그는 통화 세부사항 보기에 직접 표시되며 무제한 분석에서도 검색할 수 있습니다.

사용자 정의 스팬을 서비스에 매핑하기

일반적으로 사용자 정의 스팬을 Instana 의 애플리케이션 관점(application perspectives)에 있는 논리적 서비스와 연결하고 싶어 할 텐데, 이는 SetServicenameAPI 메서드를 호출하는 것만큼 간단합니다(이 메서드는 문자열 하나만 받습니다). SDK를 사용하여 구현된 엔드포인트를 구분하기 위해, SetEndpointNameAPI 를 통해 보다 상세한 매핑을 위한 엔드포인트를 제공할 수도 있습니다.

public void MyTracedMethod(string userName, string someSuperRelevantData)
{
    using(var span = CustomSpan.Create())
    {
        span.SetServiceName("AwesomeSDKService");
        span.SetEndpointName("TracingEndpoint");
        .
        .
        .
    }
}
 

모든 범위에서 서비스 및 엔드포인트를 설정할 수 있지만 이러한 설정은 INTERMEDIATE 범위에서 버려집니다 (마지막 선행 ENTRY에서 상속됨).

스팬의 결과 캡처하기

인스트루먼트하는 메소드가 값을 리턴한다고 가정하십시오. 추적에 이 값이 있으면 문제점 해결에 도움이 된다고 가정할 수 있습니다. APISetResult 를 방문해 보세요.

public bool MyTracedMethod(string userName, string someSuperRelevantData)
{
    using(var span = CustomSpan.Create())
    {
        bool result = span.Wrap<bool>(
            ()=>{
                // your original code here
                return resultingBoolean;
            }, true);

        span.SetResult(result.ToString());
        return result;
    }
}
 

중첩 스팬

중첩 범위는 한 메소드에서 다른 메소드를 호출하는 것만큼 쉽습니다. 예를 들어, 하나의 메소드가 항목으로 제공되는 반면 하위 범위는 중간이라고 가정할 수 있습니다.

public bool MyTracedEntryMethod(string userName, string someSuperRelevantData)
{
    using(var span = CustomSpan.CreateEntry())
    {
        bool result = span.Wrap<bool>(
            ()=>{
                List<string> data = this.GetSomeDataFromSomewhere();
                // do some heavy processing
                return theResultICameUpWith;
            }, true);

        span.SetResult(result.ToString());
        return result;
    }
}


private List<string> GetSomeDataFromSomewhere()
{
    using(var span = CustomSpan.Create())
    {
        List<string> result = span.WrapAction(
            ()=>{
                // read data from somewhere...
                return theListICameUpWith;
            }, true);

        span.SetResult(result.ToString());
        return result;
    }
}
 

이 범위의 결과는 중간 범위가 하위인 항목 범위입니다. 기술적으로 중첩에는 깊이에 대한 제한이 없지만 깊은 순환에서는 범위를 작성하지 않아야 합니다.

분산 추적에서 distributed 살펴보기

지금까지 논의된 모든 범위는 하나의 서비스로 제한되었습니다. 또한 활동을 추적하는 다른 컴포넌트에 도달하지 않았습니다. 서비스 경계에서 진정한 분산 추적을 수행하려면 일부 상관을 적용해야 합니다.

추적의 상관은 엑시트 호출에서 상관 데이터를 설정하는 방법과 이 데이터를 다시 확보하고 다른 컴포넌트의 항목에서 이 컨텍스트를 계속하는 방법을 설명합니다.

이 상관을 달성하기 위해 CustomSpan 에는 CustomSpan.CreateExitCustomSpan.CreateEntry 메소드의 오버로드가 있습니다.

CustomSpan.CreateExit 메소드는 Action<string, string> 를 인수로 사용할 수 있지만 CustomSpan.CreateEntryFunc<DistributedTraceInformation>를 사용합니다.

예를 들어, 호출하려는 원격 서비스에 전달하는 `class Message `가 있다고 가정해 봅시다.

    public class Message
    {
        public Message()
        {
            this.Tags = new Dictionary<string, string>();
        }
        public Dictionary<string, string> Tags { get; private set; }
        public int Payload { get; set; }

        public void AddTag(string tagName, string tagValue)
        {
            this.Tags.Add(tagName, tagValue);
        }
    }
 

메시지의 관련 파트는 두 개의 문자열을 사용하는 AddTag 메소드입니다. 이 메소드는 CustomSpan.CreateExit에 제공해야 하는 서명입니다.

CreateExit를 호출할 때 이 메소드를 사용하여 Message의 인스턴스에 상관 데이터를 작성합니다.

public void MyLocalEntryMethod()
{
    // this methd will create an entry span and then call our method
    // that communicates with the remote-service (and thus create our exit span)
    using(var span = CustomSpan.CreateEntry())
    {
        span.WrapAction(()=>{
            CallRemoteService();
        })
    }
}

public void CallRemoteService()
{
    Message message = new Message();
    using(var exitSpan = CustomSpan.CreateExit(this, message.AddTag))
    {
        exitSpan.WrapAction( ()=>{
            var service = new RemoteService();
            service.ValidateRequest(message);
        }
    }
}
 

따라서 메시지가 service.ValidateRequest(message)에 대한 호출을 사용하여 로컬 컴포넌트의 범위를 벗어날 때 메시지는 태그 목록에 상관 데이터를 전달합니다. 이러한 태그가 피호출자 사이트에서 추출되는 방법을 볼 수 있습니다.

public void ValidateRequest(Message message)
{
    using(var span = CustomSpan.CreateEntry(this, ()=>ExtractCorrelationData(message))
    {
        // do whatever this method is supposed to do, we only care for extraction
        // if the correlation-data anyway :-)
    }
}

private DistributedTraceInformation ExtractCorrelationData(Message message)
{
    var dti = new DistributedTraceInformation();
    dti.ParentSpanId = Convert.ToInt64(message.Tags[TracingConstants.ExternalParentSpanIdHeader], 16);
    dti.TraceId = Convert.ToInt64(message.Tags[TracingConstants.ExternalTraceIdHeader], 16);
    return dti;
}
 

메시지의 관련 파트는 ExtractCorrelationData입니다. 엑시트 작성 시 Message.AddTag 메소드를 사용했기 때문에 SDK가 메시지를 서비스에 전송하기 전에 SDK가 관련 ID (parent-span-id및 trace-id) 를 메시지의 태그 목록에 기록합니다.

이제 서비스는 태그를 읽어 이러한 값을 다시 추출할 수 있습니다 (이전 코드에서 키로 사용되는 상수로 식별할 수 있음). 사용자가 작성하는 DistributedTraceInformation의 인스턴스는 SDK에서 기존 추적에 새로 작성된 엑시트를 추가하는 데 사용됩니다. 따라서 사용자가 작성하는 항목 범위는 로컬 서비스에 있는 엑시트의 상대입니다.

트레이스 분할

자동화된 추적이 너무 많이 수행되고 작성되는 추적이 너무 길어서 이해할 수 없는 예제를 찾을 수 있습니다. 예를 들어, 이러한 인스턴스는 서버가 장기 실행 백그라운드 태스크의 진행에 대한 콜백을 통해 클라이언트에 업데이트를 푸시할 때 장기 양방향 WCF 통신에서 발생할 수 있습니다. 이러한 통신으로 인해 긴 트레이스가 생성되는데, 이 트레이스는 Instana UI에 표시하기에는 너무 길 수 있습니다.

이러한 경우, 추적을 여러 추적으로 나눌 수 있습니다. 보다 구체적으로, 클라이언트에 대한 각 콜백을 별도의 추적으로 구분할 수 있습니다. 이 옵션을 사용하기 위해 CustomSpan 에서 CreateEntryForNewTrace 를 사용하여 현재 추적을 중지하고 해당 지점에서 새 추적을 작성할 수 있습니다. 클라이언트에 대한 호출 바로 전에 서버 측에서 이를 수행할 수 있습니다.

var callbackChanell = OperationContext.Current.GetCallbackChannel<IMathResult>();
if (callbackChanell != null)
{
    using (var span = CustomSpan.CreateEntryForNewTrace(this))
    {
        callbackChanell.SendStatusUpdate(new MathArguments() { InParam = args.InParam, Progress = (float)i / args.InParam, Result = generator.Next(1000, 9999) });
    }
}
 

.NET 속성을 활용한 선언형 SDK

Instana 선언형 SDK는 속성 기반 접근 방식을 통해 .NET Core 애플리케이션에서 자동 분산 추적을 지원합니다. `trace` [InstanaTrace] 속성을 사용하여 메서드를 선언하면, 별도의 추적 코드를 작성하지 않고도 추적 로그를 생성할 수 있습니다.

이 SDK는 다음과 같은 기능을 지원합니다:

  • 설정 가능한 구간 유형 (ENTRY, INTERMEDIATE, EXIT)
  • 사용자 정의 스팬 이름
  • 메서드 인자와 반환값의 자동 캡처
  • 사용자 정의 태그
  • 내장형 민감 정보 마스킹 기능

인스트루멘테이션은 재작성 방식을 통해 런타임 시 투명하게 적용되며, INSTANA_NET_ATTR_SDK_TRACING 환경 변수만 활성화하면 됩니다. 이러한 선언적 접근 방식은 복잡한 코딩 작업을 줄여주면서도 추적 동작을 세밀하게 제어할 수 있게 해주므로, 추적에 대한 깊은 전문 지식 없이도 분산형 가시성을 활용할 수 있게 해줍니다.

작동 방식

다음 단계에서는 선언형 SDK의 작동 방식을 설명합니다:

  1. 속성 추가 - 메서드에 를 [InstanaTrace] 적용하고 추적 옵션을 구성합니다.
  2. 자동 감지 - ` Instana ` 프로파일러는 런타임 시 해당 속성을 감지합니다.
  3. 바이트코드 삽입 - 메서드 주변에 추적 코드가 자동으로 삽입됩니다.
  4. 스팬 생성 - Instana 는 스팬 생성, 데이터 수집 및 컨텍스트 전파를 자동으로 처리합니다.

별도의 설정 파일이나 수동 설정은 필요하지 않습니다. 속성을 추가하면 추적 기능이 작동합니다.

참고: 속성 기반 추적을 활성화하려면 환경 변수를 설정하십시오 INSTANA_NET_ATTR_SDK_TRACING=true.

다음 예제는 코드에서 속성을 사용하여 진입(Entry) 및 이탈(Exit) 구간을 생성하는 방법을 보여줍니다.

기본 항목 범위

[InstanaTrace(SpanKind = SpanKind.ENTRY, SpanName = "ProcessOrder")]
public string ProcessOrder(int orderId)
{
    return "Order processed";
}
 

이 메서드에 대해 다음 스팬이 생성됩니다:

{
    "sdk.type": "ENTRY",
    "sdk.name": "ProcessOrder",
    "custom.args.orderId": "12345",
    "custom.result": "Order processed"
}
 

서비스 정보가 포함된 스팬 종료

Exit는 외부 서비스, 데이터베이스 또는 API로 발신되는 호출을 처리합니다. 이들은 서비스 정보를 수집하고 시스템 경계를 넘어 분산 추적을 가능하게 합니다.

[InstanaTrace(
    SpanKind = SpanKind.EXIT,
    ServiceName = "UserService",
    EndpointName = "/api/users/fetch")]
public User GetUser(string userId)
{
    return new User { Id = userId };
}
 

민감 정보 보호

이 SDK는 일반적인 보안 관련 키워드가 포함된 메서드 매개변수와 반환값을 자동으로 가려 민감한 데이터를 보호합니다. 이름에 password, secret, token, apikey, api_key, 또는 credentials (대소문자 구분 없음)이 포함된 매개변수는 캡처된 스팬 데이터 내에서 자동으로 ***REDACTED*** 로 대체됩니다. 이를 통해 추적 기록에 민감한 정보가 실수로 노출되는 것을 방지합니다.

[InstanaTrace]
public bool Authenticate(string username, string password)
{
    return true;
}
 
{
    "custom.args.username": "john_doe",
    "custom.args.password": "[REDACTED]"
}
 

문제점 해결

Declarative SDK 사용 중 문제가 발생하면 다음 사항을 확인해 보세요:

  1. 환경 변수가 로 INSTANA_NET_ATTR_SDK_TRACING 설정되어 true있는지 확인하십시오.
  2. Instana 프로파일러가 애플리케이션에 올바르게 연결되어 있는지 확인하십시오.
  3. 프로젝트에 SDK와 프로파일러/리라이터 패키지가 모두 참조되어 있는지 확인하십시오.

스팬이 캡처되지 않는 경우, 다음 사항을 확인해 주십시오:

  1. 애플리케이션 실행 중에 계측된 메서드가 호출되는지 확인하십시오.
  2. 프로파일러 로그를 검토하여 재작성이 정상적으로 수행되고 있는지 확인하십시오.
  3. 추적 데이터가 Instana 백엔드로 올바르게 전송되는지 확인하십시오.

.NET 또는 .NET Core SDK에 대해 궁금한 점이 있으시면 IBM 지원팀에 문의해 주십시오.