Amazon EC2에서 Error Reporting 설정

다음 두 가지 방법 중 하나로 EC2 애플리케이션에서 Error Reporting으로 오류를 보낼 수 있습니다.

  • Cloud Logging에 로깅. Cloud Logging을 이미 사용 중인 경우 유일한 추가 요구사항은 Error Reporting에서 로그 항목을 인식할 수 있어야 한다는 것입니다. 오류 형식 지정 요구사항에 대한 자세한 내용은 Cloud Logging의 형식 지정 오류를 참조하세요.

  • Error Reporting API 사용. 애플리케이션은 REST API를 사용하여 HTTP 요청을 보내거나 여러 언어로 실험용 라이브러리를 활용할 수 있습니다.

Logging을 사용해 오류 보고하기

EC2 애플리케이션을 Error Reporting에 연결하려면 예외 또는 기타 오류를 Logging에 전송합니다.

예를 들면 다음과 같습니다.

  1. Amazon Web Services(AWS) 시스템을 Google Cloud에 연결합니다. 자세한 내용은 개별 VM에 Logging 에이전트 설치를 참조하세요.
  2. 사용자 환경에 적합한 google-fluentd 에이전트를 설치합니다. 자세한 내용은 Logging 에이전트 설치를 참조하세요.
  3. Logging에 예외 및 스택 트레이스를 로깅하도록 애플리케이션을 수정합니다.

    스택 트레이스의 모든 프레임을 포함하여 단일 오류 또는 예외에 대한 모든 정보를 동일한 로그 항목에 포함해야 합니다. 모든 정보가 함께 표시되지 않으면 Error Reporting이 오류를 감지하지 못할 수 있습니다. 로그 항목 페이로드에 대해 구조화된 JSON 형식을 사용하여 각 오류에 다양한 종류의 정보를 포함할 수 있습니다.

  4. 자바

    pom.xml 파일에 다음을 추가합니다.

    <dependency>
      <groupId>org.fluentd</groupId>
      <artifactId>fluent-logger</artifactId>
      <version>0.3.4</version>
    </dependency>

    그런 다음 다음과 같은 코드를 사용하여 예외 데이터를 보냅니다.

    public class ExceptionUtil {
      private static FluentLogger ERRORS = FluentLogger.getLogger("myapp");
    
      public static void main(String[] args) {
        try {
          throw new Exception("Generic exception for testing Stackdriver");
        } catch (Exception e) {
          report(e);
        }
      }
    
      public static void report(Throwable ex) {
        StringWriter exceptionWriter = new StringWriter();
        ex.printStackTrace(new PrintWriter(exceptionWriter));
        Map<String, Object> data = new HashMap<>();
        data.put("message", exceptionWriter.toString());
        Map<String, String> serviceContextData = new HashMap<>();
        serviceContextData.put("service", "myapp");
        data.put("serviceContext", serviceContextData);
        // ... add more metadata
        ERRORS.log("errors", data);
      }
    }

    Python

    먼저 fluent-logger-python 라이브러리를 설치합니다.

    sudo pip install fluent-logger
    

    그런 다음 다음과 같은 코드를 사용하여 예외 데이터를 보냅니다.

    import traceback
    
    import fluent.event
    import fluent.sender
    
    
    def simulate_error():
        fluent.sender.setup("myapp", host="localhost", port=24224)
    
        def report(ex):
            data = {}
            data["message"] = "{0}".format(ex)
            data["serviceContext"] = {"service": "myapp"}
            # ... add more metadata
            fluent.event.Event("errors", data)
    
        # report exception data using:
        try:
            # simulate calling a method that's not defined
            raise NameError
        except Exception:
            report(traceback.format_exc())
    
    

    Node.js

    먼저 fluent-logger-node 라이브러리를 설치합니다.

    npm install --save fluent-logger
    

    그런 다음 다음과 같은 코드를 사용하여 예외 데이터를 보냅니다.

    const structuredLogger = require('fluent-logger').createFluentSender('myapp', {
      host: 'localhost',
      port: 24224,
      timeout: 3.0,
    });
    
    const report = (err, req) => {
      const payload = {
        serviceContext: {
          service: 'myapp',
        },
        message: err.stack,
        context: {
          httpRequest: {
            url: req.originalUrl,
            method: req.method,
            referrer: req.header('Referer'),
            userAgent: req.header('User-Agent'),
            remoteIp: req.ip,
            responseStatusCode: 500,
          },
        },
      };
      structuredLogger.emit('errors', payload);
    };
    
    // Handle errors (the following uses the Express framework)
    // eslint-disable-next-line no-unused-vars
    app.use((err, req, res, next) => {
      report(err, req);
      res.status(500).send(err.response || 'Something broke!');
    });

    Go

    먼저 fluent-logger-golang 패키지를 설치합니다.

    go get github.com/fluent/fluent-logger-golang/
    

    그런 다음 다음과 같은 코드를 사용하여 오류 데이터를 보냅니다.

    
    package main
    
    import (
    	"log"
    	"net/http"
    	"os"
    	"runtime"
    
    	"github.com/fluent/fluent-logger-golang/fluent"
    )
    
    var logger *fluent.Fluent
    
    func main() {
    	var err error
    	logger, err = fluent.New(fluent.Config{
    		FluentHost: "localhost",
    		FluentPort: 24224,
    	})
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	http.HandleFunc("/demo", demoHandler)
    
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    	}
    	log.Printf("Listening on port %s", port)
    	if err := http.ListenAndServe(":"+port, nil); err != nil {
    		log.Fatal(err)
    	}
    }
    
    func report(stackTrace string, r *http.Request) {
    	payload := map[string]interface{}{
    		"serviceContext": map[string]interface{}{
    			"service": "myapp",
    		},
    		"message": stackTrace,
    		"context": map[string]interface{}{
    			"httpRequest": map[string]interface{}{
    				"method":    r.Method,
    				"url":       r.URL.String(),
    				"userAgent": r.UserAgent(),
    				"referrer":  r.Referer(),
    				"remoteIp":  r.RemoteAddr,
    			},
    		},
    	}
    	if err := logger.Post("myapp.errors", payload); err != nil {
    		log.Print(err)
    	}
    }
    
    // Handler for the incoming requests.
    func demoHandler(w http.ResponseWriter, r *http.Request) {
    	// How to handle a panic.
    	defer func() {
    		if e := recover(); e != nil {
    			stack := make([]byte, 1<<16)
    			stackSize := runtime.Stack(stack, true)
    			report(string(stack[:stackSize]), r)
    		}
    	}()
    
    	// Panic is triggered.
    	x := 0
    	log.Println(100500 / x)
    }
    

    Error Reporting API를 사용하여 오류 쓰기

    Error Reporting API는 서비스에 오류 정보를 작성하기 위한 report 엔드포인트를 제공합니다.

    1. Enable the Error Reporting API.

      Enable the API

    2. REST API 또는 클라이언트 라이브러리를 사용하여 오류를 API로 보고합니다.

      • REST API

        API에 대한 자세한 내용은 참고 문서를 확인하세요.

      • 클라이언트 라이브러리 사용

        라이브러리는 제한된 언어에 대해 제공되며 애플리케이션에서 Error Reporting API를 호출하는 데 도움이 됩니다.

    샘플

    ASP.NET

    ASP.NET NuGet 패키지는 ASP.NET 웹 애플리케이션에서 포착되지 않은 예외를 Error Reporting으로 보고합니다.

    NuGet 패키지 설치

    Visual Studio에서 Stackdriver ASP.NET NuGet 패키지를 설치하려면 다음 단계를 따르세요.

    1. 솔루션을 마우스 오른쪽 버튼으로 클릭하고 Manage NuGet packages for solution(솔루션용 NuGet 패키지 관리)를 선택합니다.
    2. Include prerelease(사전 출시 포함) 체크박스를 선택합니다.
    3. 이름이 Google.Cloud.Diagnostics.AspNet인 패키지를 검색하여 설치합니다.

    사용

    Stackdriver ASP.NET NuGet 패키지를 설치했으면 애플리케이션 코드에 다음 문을 추가하여 Stackdriver로 오류 보내기를 시작합니다.

    using Google.Cloud.Diagnostics.AspNet;
    

    다음 HttpConfiguration 코드를 .NET 웹 앱(your-project-id를 실제 프로젝트 ID로 바꿈)의 Register 메서드에 추가하여 예외 보고를 사용 설정합니다.

    public static void Register(HttpConfiguration config)
    {
        string projectId = "YOUR-PROJECT-ID";
        string serviceName = "NAME-OF-YOUR-SERVICE";
        string version = "VERSION-OF-YOUR-SERVCICE";
        // ...
        // Add a catch all for the uncaught exceptions.
        config.Services.Add(typeof(IExceptionLogger),
            ErrorReportingExceptionLogger.Create(projectId, serviceName, version));
        // ...
    }
    

    이 메서드를 ASP.NET 애플리케이션에 추가하면 Google Cloud 콘솔의 Error Reporting 섹션에서 Google Cloud에 보고될 때 발생하는 포착되지 않은 예외를 볼 수 있습니다.

    C#

    다음 예시는 GoogleCloudPlatform/dotnet-docs-samples 저장소에서 찾을 수 있습니다. 사용하려면 프로젝트를 빌드한 후 프로젝트 ID를 지정합니다.

    C:\...\bin\Debug> set GOOGLE_PROJECT_ID=[YOUR_PROJECT_ID]
    

    [YOUR_PROJECT_ID]를 Google Cloud 콘솔의 올바른 값으로 바꿉니다.

    그런 다음 다음과 유사한 코드로 예외 데이터를 보냅니다.

    public class ErrorReportingSample
    {
        public static void Main(string[] args)
        {
            try
            {
                throw new Exception("Generic exception for testing Stackdriver Error Reporting");
            }
            catch (Exception e)
            {
                report(e);
                Console.WriteLine("Stackdriver Error Report Sent");
            }
        }
    
        /// <summary>
        /// Create the Error Reporting service (<seealso cref="ClouderrorreportingService"/>)
        /// with the Application Default Credentials and the proper scopes.
        /// See: https://developers.google.com/identity/protocols/application-default-credentials.
        /// </summary>
        private static ClouderrorreportingService CreateErrorReportingClient()
        {
            // Get the Application Default Credentials.
            GoogleCredential credential = GoogleCredential.GetApplicationDefaultAsync().Result;
    
            // Add the needed scope to the credentials.
            credential.CreateScoped(ClouderrorreportingService.Scope.CloudPlatform);
    
            // Create the Error Reporting Service.
            ClouderrorreportingService service = new ClouderrorreportingService(new BaseClientService.Initializer
            {
                HttpClientInitializer = credential,
            });
            return service;
        }
    
        /// <summary>
        /// Creates a <seealso cref="ReportRequest"/> from a given exception.
        /// </summary>
        private static ReportRequest CreateReportRequest(Exception e)
        {
            // Create the service.
            ClouderrorreportingService service = CreateErrorReportingClient();
    
            // Get the project ID from the environement variables.
            string projectId = Environment.GetEnvironmentVariable("GOOGLE_PROJECT_ID");
    
            // Format the project id to the format Error Reporting expects. See:
            // https://cloud.google.com/error-reporting/reference/rest/v1beta1/projects.events/report
            string formattedProjectId = string.Format("projects/{0}", projectId);
    
            // Add a service context to the report.  For more details see:
            // https://cloud.google.com/error-reporting/reference/rest/v1beta1/projects.events#ServiceContext
            ServiceContext serviceContext = new ServiceContext()
            {
                Service = "myapp",
                Version = "8c1917a9eca3475b5a3686d1d44b52908463b989",
            };
            ReportedErrorEvent errorEvent = new ReportedErrorEvent()
            {
                Message = e.ToString(),
                ServiceContext = serviceContext,
            };
            return new ReportRequest(service, errorEvent, formattedProjectId);
        }
    
        /// <summary>
        /// Report an exception to the Error Reporting service.
        /// </summary>
        private static void report(Exception e)
        {
            // Create the report and execute the request.
            ReportRequest request = CreateReportRequest(e);
            request.Execute();
        }
    }

    Go

    Go용 Error Reporting 설정을 참조하세요.

    자바

    자바용 Error Reporting 설정을 참조하세요.

    Node.js

    Node.js용 Error Reporting 설정을 참조하세요.

    Ruby

    Ruby용 Error Reporting 설정을 참조하세요.

    Python

    Python용 Error Reporting 설정을 참조하세요.

    PHP

    PHP용 Error Reporting 설정을 참조하세요.

    오류 그룹 보기

    Google Cloud 콘솔에서 Error Reporting 페이지로 이동합니다.

    Error Reporting으로 이동

    검색창을 사용하여 이 페이지를 찾을 수도 있습니다.