.NET 클라이언트 라이브러리는 로깅 목적으로 gRPC 인터셉터를 내부적으로 사용하지만, 사용자는 자체 커스텀 gRPC 인터셉터를 추가해야 합니다. 이 기능은 측정항목을 맞춤 로그 애그리게이터로 전송하거나 Google Ads API 요청을 변환할 수 있습니다.
커스텀 gRPC 인터셉터를 추가하려면
Grpc.Core.Interceptors.Interceptor
클래스를 열고
AddInterceptor
메서드로 GoogleAdsClient
호출
스트리밍 및 비 스트리밍 gRPC 요청을 가로채려면
Interceptor
클래스의 서로 다른 두 메서드를 재정의합니다.
각각 AsyncUnaryCall
및 AsyncServerStreamingCall
입니다.
Google.Ads.Gax.Interceptors
네임스페이스는 다음과 같은 유틸리티 클래스를 제공합니다.
예외 처리를 용이하게 하기 위해 커스텀 인터셉터에 사용됩니다.
다음 코드 예에서는 스트리밍 및 비 스트리밍 gRPC를 모두 구현합니다. 호출 인터셉터:
// Copyright 2024 Google LLC // // Licensed 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. using CommandLine; using Google.Api.Gax; using Google.Ads.Gax.Examples; using Google.Ads.Gax.Interceptors; using Google.Ads.GoogleAds.Lib; using Google.Ads.GoogleAds.V17.Errors; using Google.Ads.GoogleAds.V17.Services; using Grpc.Core; using Grpc.Core.Interceptors; using System; using System.Threading.Tasks; namespace Google.Ads.GoogleAds.Examples.V17 { /// <summary> /// This code example shows how to add a custom gRPC interceptor. /// </summary> public class AddCustomGrpcInterceptor : ExampleBase { /// <summary> /// Command line options for running the <see cref="AddCustomGrpcInterceptor"/> example. /// </summary> public class Options : OptionsBase { /// <summary> /// The Google Ads customer ID for which the call is made. /// </summary> [Option("customerId", Required = true, HelpText = "The Google Ads customer ID for which the call is made.")] public long CustomerId { get; set; } } /// <summary> /// Main method, to run this code example as a standalone application. /// </summary> /// <param name="args">The command line arguments.</param> public static void Main(string[] args) { Options options = ExampleUtilities.ParseCommandLine<Options>(args); AddCustomGrpcInterceptor codeExample = new AddCustomGrpcInterceptor(); Console.WriteLine(codeExample.Description); GoogleAdsClient client = new GoogleAdsClient(); // Add a custom interceptor. client.AddInterceptor(new CustomInterceptor()); codeExample.Run(client, options.CustomerId); } /// <summary> /// Returns a description about the code example. /// </summary> public override string Description => "This code example shows how to add a custom gRPC interceptor."; /// <summary> /// Runs the code example. /// </summary> /// <param name="client">The Google Ads client.</param> /// <param name="customerId">The Google Ads customer ID for which the call is made.</param> public void Run(GoogleAdsClient client, long customerId) { // Get the GoogleAdsService. GoogleAdsServiceClient googleAdsService = client.GetService( Services.V17.GoogleAdsService); // Create a query that will retrieve all campaigns, just to demonstrate usage of the // custom interceptor. string query = @"SELECT campaign.id, FROM campaign ORDER BY campaign.id"; try { // Issue a streaming search request; we don't need to do anything with the response // here, we just want to demonstrate usage of the interceptor. googleAdsService.SearchStream(customerId.ToString(), query, delegate (SearchGoogleAdsStreamResponse resp){} ); } catch (GoogleAdsException e) { Console.WriteLine("Failure:"); Console.WriteLine($"Message: {e.Message}"); Console.WriteLine($"Failure: {e.Failure}"); Console.WriteLine($"Request ID: {e.RequestId}"); throw; } try { // Issue a non-streaming call. PagedEnumerable<SearchGoogleAdsResponse, GoogleAdsRow> response = googleAdsService.Search(customerId.ToString(), query); foreach (GoogleAdsRow googleAdsRow in response) { // The response for Search is lazy, meaning that the actual gRPC call will be // sent only when the response is actually accessed; to demonstrate usage of // the interceptor, then, we need to ensure the call is sent by looping // through the response results. Console.WriteLine("Campaign with ID {0} was found.", googleAdsRow.Campaign.Id, googleAdsRow.Campaign.Name); } } catch (GoogleAdsException e) { Console.WriteLine("Failure:"); Console.WriteLine($"Message: {e.Message}"); Console.WriteLine($"Failure: {e.Failure}"); Console.WriteLine($"Request ID: {e.RequestId}"); throw; } } } /// <summary> /// A custom interceptor for both streaming and non-streaming gRPC calls. /// </summary> internal class CustomInterceptor : Interceptor { public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>( TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuationCallback) { AsyncUnaryCall<TResponse> call = continuationCallback(request, context); Action<Task<TResponse>> callback = delegate (Task<TResponse> oldTask) { Console.WriteLine($"Intercepted a non-streaming call to {context.Method.Name}"); }; return UnaryRpcInterceptor.Intercept(call, callback); } public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>( TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncServerStreamingCallContinuation<TRequest, TResponse> continuation) { AsyncServerStreamingCall<TResponse> call = continuation(request, context); StreamingRpcInterceptor<TResponse> responseStream = null; responseStream = new StreamingRpcInterceptor<TResponse>(call.ResponseStream, delegate (TResponse response, AggregateException rpcException) { Console.WriteLine($"Intercepted a streaming call to {context.Method.Name}"); }); return new AsyncServerStreamingCall<TResponse>( responseStream, call.ResponseHeadersAsync, call.GetStatus, call.GetTrailers, call.Dispose ); } } }