go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/bisection/compilefailureanalysis/compilelog/compile_log.go (about)

     1  // Copyright 2022 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package compilelogs handles downloading logs for compile failures
    16  package compilelog
    17  
    18  import (
    19  	"context"
    20  	"encoding/json"
    21  	"fmt"
    22  
    23  	"go.chromium.org/luci/bisection/internal/logdog"
    24  	"go.chromium.org/luci/bisection/model"
    25  	"go.chromium.org/luci/bisection/util"
    26  
    27  	"go.chromium.org/luci/bisection/internal/buildbucket"
    28  
    29  	buildbucketpb "go.chromium.org/luci/buildbucket/proto"
    30  	"go.chromium.org/luci/common/logging"
    31  	"google.golang.org/protobuf/types/known/fieldmaskpb"
    32  )
    33  
    34  // GetCompileLogs gets the compile log for a build bucket build
    35  // Returns the ninja log and stdout log
    36  func GetCompileLogs(c context.Context, bbid int64) (*model.CompileLogs, error) {
    37  	build, err := buildbucket.GetBuild(c, bbid, &buildbucketpb.BuildMask{
    38  		Fields: &fieldmaskpb.FieldMask{
    39  			Paths: []string{"steps"},
    40  		},
    41  	})
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  	ninjaUrl := ""
    46  	stdoutUrl := ""
    47  	for _, step := range build.Steps {
    48  		if util.IsCompileStep(step) {
    49  			for _, log := range step.Logs {
    50  				if log.Name == "json.output[ninja_info]" {
    51  					ninjaUrl = log.ViewUrl
    52  				}
    53  				if log.Name == "stdout" {
    54  					stdoutUrl = log.ViewUrl
    55  				}
    56  			}
    57  			break
    58  		}
    59  	}
    60  
    61  	ninjaLog := &model.NinjaLog{}
    62  	stdoutLog := ""
    63  
    64  	// TODO(crbug.com/1295566): Parallelize downloading ninja & stdout logs
    65  	if ninjaUrl != "" {
    66  		log, err := logdog.GetLogFromViewUrl(c, ninjaUrl)
    67  		if err != nil {
    68  			logging.Errorf(c, "Failed to get ninja log: %v", err)
    69  		}
    70  		if err = json.Unmarshal([]byte(log), ninjaLog); err != nil {
    71  			return nil, fmt.Errorf("Failed to unmarshal ninja log %w. Log: %s", err, log)
    72  		}
    73  	}
    74  
    75  	if stdoutUrl != "" {
    76  		stdoutLog, err = logdog.GetLogFromViewUrl(c, stdoutUrl)
    77  		if err != nil {
    78  			logging.Errorf(c, "Failed to get stdout log: %v", err)
    79  		}
    80  	}
    81  
    82  	if len(ninjaLog.Failures) > 0 || stdoutLog != "" {
    83  		return &model.CompileLogs{
    84  			NinjaLog:  ninjaLog,
    85  			StdOutLog: stdoutLog,
    86  		}, nil
    87  	}
    88  
    89  	return nil, fmt.Errorf("Could not get compile log from build %d", bbid)
    90  }
    91  
    92  func GetFailedTargets(compileLogs *model.CompileLogs) []string {
    93  	if compileLogs.NinjaLog == nil {
    94  		return []string{}
    95  	}
    96  	results := []string{}
    97  	for _, failure := range compileLogs.NinjaLog.Failures {
    98  		results = append(results, failure.OutputNodes...)
    99  	}
   100  	return results
   101  }