Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
feat: improved logging, with levels and new CLI commands
Browse files Browse the repository at this point in the history
  • Loading branch information
temsa committed Aug 9, 2018
1 parent 8d5d4b6 commit 92f677d
Show file tree
Hide file tree
Showing 24 changed files with 790 additions and 732 deletions.
19 changes: 17 additions & 2 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,7 @@
[[constraint]]
name = "github.com/gen2brain/go-unarr"
revision = "2adf16213a3c6333c47708458fe777f9e193e396"

[[constraint]]
name = "github.com/sirupsen/logrus"
version = "1.0.6"
6 changes: 3 additions & 3 deletions analyzer/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package analyzer
import (
"errors"
"fmt"
"log"

"github.com/nearform/gammaray/nodepackage"
"github.com/nearform/gammaray/packagelockrunner"
Expand All @@ -12,6 +11,7 @@ import (
"github.com/nearform/gammaray/vulnfetcher/nodeswg"
"github.com/nearform/gammaray/vulnfetcher/ossvulnfetcher"
"github.com/nearform/gammaray/yarnlockrunner"
log "github.com/sirupsen/logrus"
)

// OSSIndexURL URL for OSSIndex. Is not a hardcoded value to facilitate testing.
Expand Down Expand Up @@ -50,7 +50,7 @@ func packagesCleanupAndDeduplication(packageList []nodepackage.NodePackage) []no
packageMap := make(map[string]nodepackage.NodePackage)
for _, pkg := range packageList {
if pkg.Name == "" {
log.Print("Ignoring package with empty name")
log.Debug("🔍 Ignoring package with empty name")
continue
}
if pkg.Version == "" {
Expand All @@ -68,7 +68,7 @@ func packagesCleanupAndDeduplication(packageList []nodepackage.NodePackage) []no

// Analyze analyzes a path to an installed (npm install) node package
func Analyze(path string, walkers ...nodepackage.Walker) (vulnfetcher.VulnerabilityReport, error) {
fmt.Println("Will scan folder <", path, ">")
fmt.Println("🔍 Will scan folder <", path, ">")
if walkers == nil {
walkers = []nodepackage.Walker{
pathrunner.PathRunner{},
Expand Down
2 changes: 1 addition & 1 deletion analyzer/analyzer_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package analyzer

import (
"log"
log "github.com/sirupsen/logrus"
"testing"

"github.com/google/go-cmp/cmp"
Expand Down
46 changes: 23 additions & 23 deletions docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path"
"strconv"
Expand All @@ -17,6 +16,7 @@ import (
"github.com/nearform/gammaray/analyzer"
"github.com/nearform/gammaray/nodepackage"
"github.com/nearform/gammaray/vulnfetcher"
log "github.com/sirupsen/logrus"
"golang.org/x/net/context"
)

Expand All @@ -34,24 +34,24 @@ type DockerContainerConfig struct {
}

func Cleanup(path string) {
fmt.Println("Cleanup temporary docker files")
log.Infoln("Cleanup temporary docker files at <", path, ">")
err := os.RemoveAll(path)
if err != nil {
log.Println("⚠️ Could not remove temporary docker image extraction folder <", path, ">:\n", err)
log.Warnln("⚠️ Could not remove temporary docker file <", path, ">:\n", err)
}
}

func pullImageIfNecessary(ctx context.Context, imageName string, cli *docker.Client) error {
reader, err := cli.ImagePull(ctx, imageName, types.ImagePullOptions{})
if err != nil {
log.Println("⚠️ Cannot pull image <", imageName, ">, will try to use a local version")
log.Warnln("⚠️ Cannot pull image <", imageName, ">, will try to use a local version")
return nil
}

// io.Copy(os.Stdout, reader) //JSONLD pull logs
_, err = ioutil.ReadAll(reader)
if err != nil {
log.Println("Could not pull image <", imageName, ">")
log.Errorln("Could not pull image <", imageName, ">")
return err
}

Expand All @@ -61,31 +61,31 @@ func pullImageIfNecessary(ctx context.Context, imageName string, cli *docker.Cli
func extractImageArchive(tarFile string, imageFolder string, imageName string) error {
a, err := unarr.NewArchive(tarFile)
if err != nil {
log.Println("Could not open docker image <", tarFile, ">")
log.Errorln("Could not open docker image <", tarFile, ">")
return err
}
err = a.Extract(imageFolder)
if err != nil {
log.Println("Could not extract docker image <", tarFile, ">")
log.Errorln("Could not extract docker image <", tarFile, ">")
return err
}

fmt.Println("Docker image <", imageName, "> decompressed in <", imageFolder, ">")
fmt.Println("🗃 Docker image <", imageName, "> decompressed in <", imageFolder, ">")
return nil
}

func exportImageLocally(ctx context.Context, imageName string, imageFolder string, cli *docker.Client) error {
response, err := cli.ImageSave(ctx, []string{imageName})
if err != nil {
log.Println("Could not save image <", imageName, ">")
log.Errorln("Could not save image <", imageName, ">")
return err
}

tarFile := imageFolder + ".tar"

f, err := os.Create(tarFile)
if err != nil {
log.Println("Could not create image <", imageName, "> tar <", tarFile, ">")
log.Errorln("Could not create image <", imageName, "> tar <", tarFile, ">")
return err
}
io.Copy(f, response)
Expand All @@ -97,20 +97,20 @@ func exportImageLocally(ctx context.Context, imageName string, imageFolder strin
func readManifest(imageFolder string, imageName string) (*DockerImageFiles, error) {
manifestFile, err := ioutil.ReadFile(path.Join(imageFolder, "manifest.json"))
if err != nil {
log.Println("Could not open docker image manifest!")
log.Errorln("Could not open docker image manifest!")
return nil, err
}
var manifests []DockerImageFiles
err = json.Unmarshal(manifestFile, &manifests)
if err != nil {
log.Println("Could not unmarshal docker image manifest!")
log.Errorln("Could not unmarshal docker image manifest!")
return nil, err
}
if len(manifests) < 1 {
return nil, fmt.Errorf("docker image '%s' manifest.json does not contain enough data", imageName)
}
if len(manifests) > 1 {
log.Println("⚠️ Will only analyze what is described by the first entry of the manifest.json of image <", imageName, "> : for more details, check ", path.Join(imageFolder, "manifest.json"))
log.Warnln("⚠️ Will only analyze what is described by the first entry of the manifest.json of image <", imageName, "> : for more details, check ", path.Join(imageFolder, "manifest.json"))
}

return &manifests[0], nil
Expand All @@ -119,16 +119,16 @@ func readManifest(imageFolder string, imageName string) (*DockerImageFiles, erro
func extractLayers(imageFolder string, snapshotPath string, manifest *DockerImageFiles) error {
for _, layerFile := range manifest.Layers {
layerPath := path.Join(imageFolder, layerFile)
fmt.Println("Decompressing layer <", layerPath, ">")
log.Debugln("🗃 Decompressing layer <", layerPath, ">")

a, err := unarr.NewArchive(layerPath)
if err != nil {
log.Println("Could not read layer <", layerPath, ">!")
log.Errorln("🗃 Could not read layer <", layerPath, ">!")
return err
}
err = a.Extract(snapshotPath)
if err != nil {
log.Println("Could not extract layer <", layerPath, ">!")
log.Errorln("Could not extract layer <", layerPath, ">!")
return err
}
}
Expand All @@ -138,15 +138,15 @@ func extractLayers(imageFolder string, snapshotPath string, manifest *DockerImag
func readImageConfig(imageFolder string, manifest *DockerImageFiles) (*DockerConfig, error) {
configFile, err := ioutil.ReadFile(path.Join(imageFolder, manifest.Config))
if err != nil {
log.Println("Could not open docker image configuration!")
log.Errorln("Could not open docker image configuration!")
return nil, err
}

fmt.Println("Read docker image configuration...")
log.Infoln("🗃 Read docker image configuration...")
var config DockerConfig
err = json.Unmarshal(configFile, &config)
if err != nil {
log.Println("Could not unmarshal docker image configuration!")
log.Errorln("Could not unmarshal docker image configuration!")
return nil, err
}
return &config, nil
Expand All @@ -157,7 +157,7 @@ func ScanImage(imageName string, projectPath string, walkers ...nodepackage.Walk
ctx := context.Background()
cli, err := docker.NewEnvClient()
if err != nil {
log.Println("Could not connect to docker")
log.Errorln("Could not connect to docker")
return nil, err
}

Expand All @@ -177,7 +177,7 @@ func ScanImage(imageName string, projectPath string, walkers ...nodepackage.Walk
if err != nil {
return nil, err
}
fmt.Println("Decompressing docker image layers...")
log.Infoln("🗃 Decompressing docker image layers...")

snapshotPath := path.Join(imageFolder, "snapshot")

Expand All @@ -192,10 +192,10 @@ func ScanImage(imageName string, projectPath string, walkers ...nodepackage.Walk
}
imageProjectPath := config.ContainerConfig.WorkingDir
if projectPath != "" {
fmt.Println("Using provided -path <", projectPath, "> instead of docker's working directory <", config.ContainerConfig.WorkingDir, ">")
log.Infoln("🗃 Using provided -path <", projectPath, "> instead of docker's working directory <", config.ContainerConfig.WorkingDir, ">")
imageProjectPath = projectPath
}

fmt.Println("Analyze image stored in <", imageProjectPath, ">")
fmt.Println("🗃 Analyze package stored at <", imageProjectPath, "> in image <", imageName, ">...")
return analyzer.Analyze(path.Join(imageFolder, "snapshot", imageProjectPath), walkers...)
}
2 changes: 1 addition & 1 deletion docker/docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package docker
import (
"context"
"fmt"
"log"
log "github.com/sirupsen/logrus"
"os"
"path"
"testing"
Expand Down
35 changes: 32 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package main

import (
"fmt"
"log"
"os"
"strings"

"github.com/jaffee/commandeer"
"github.com/nearform/gammaray/analyzer"
Expand All @@ -13,13 +13,16 @@ import (
"github.com/nearform/gammaray/pathrunner"
"github.com/nearform/gammaray/vulnfetcher"
"github.com/nearform/gammaray/yarnlockrunner"
log "github.com/sirupsen/logrus"
)

// Args CLI arguments
type Args struct {
Path string `help:"path to installed Node package (locally or inside the container, depending if 'image' is provided)"`
Image string `help:"analyze this docker image"`
LogFile string `help:"in which file to put the detailed logs"`
LogLevel string `help:"minimal level that should be logged"`
LogAsJSON bool `help:"detailed logs should be formated as JSON if true (default: false)"`
OnlyInstalled bool `help:"force only installed module checking usage (default false: use it as the main strategy then use other fallbacks)"`
OnlyPackageLock bool `help:"force only <package-lock.json> usage (default false: use it as a fallback)"`
OnlyYarnLock bool `help:"force only <yarn.lock> usage (default false: use it as a fallback)"`
Expand All @@ -31,6 +34,8 @@ func Defaults() *Args {
Path: "",
Image: "",
LogFile: ".gammaray.log",
LogLevel: "info",
LogAsJSON: false,
OnlyInstalled: false,
OnlyPackageLock: false,
OnlyYarnLock: false,
Expand All @@ -46,8 +51,32 @@ func main() {
}
}

func (m *Args) getLogLevel() log.Level {

switch strings.ToLower(strings.TrimSpace(m.LogLevel)) {
case "panic":
return log.PanicLevel
case "fatal":
return log.FatalLevel
case "error":
return log.ErrorLevel
case "warn":
return log.WarnLevel
case "info":
return log.InfoLevel
case "debug":
return log.DebugLevel
default:
return log.InfoLevel
}
}

// Run the program once CLI args are parsed
func (m *Args) Run() error {
if m.LogAsJSON == true {
log.SetFormatter(&log.JSONFormatter{})
}
log.SetLevel(m.getLogLevel())
f, err := os.OpenFile(m.LogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
fmt.Printf("Error opening log file: %v", err)
Expand Down Expand Up @@ -80,9 +109,9 @@ func (m *Args) Analyze() (vulnfetcher.VulnerabilityReport, error) {
return analyzer.Analyze(m.Path, walkers...)
} else if m.Image != "" {
if m.Path != "" {
fmt.Println("Will scan folder <", m.Path, "> from docker image <", m.Image, ">")
fmt.Println("🔍 Will scan folder <", m.Path, "> from docker image <", m.Image, ">")
} else {
fmt.Println("Will scan docker image <", m.Image, ">")
fmt.Println("🔍 Will scan docker image <", m.Image, ">")
}

return docker.ScanImage(m.Image, m.Path, walkers...)
Expand Down
13 changes: 9 additions & 4 deletions main_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package main

import (
"log"
"os"
"path"
"testing"

"github.com/google/go-cmp/cmp"
log "github.com/sirupsen/logrus"
)

var testLogFile = path.Join(os.TempDir(), "gammaray-log-test")
Expand Down Expand Up @@ -122,9 +122,14 @@ func TestImageHelloWorld(t *testing.T) {

func TestDefaults(t *testing.T) {
expected := Args{
Path: "",
Image: "",
LogFile: ".gammaray.log",
Path: "",
Image: "",
LogFile: ".gammaray.log",
LogLevel: "info",
LogAsJSON: false,
OnlyInstalled: false,
OnlyPackageLock: false,
OnlyYarnLock: false,
}

if diff := cmp.Diff(*Defaults(), expected); diff != "" {
Expand Down
Loading

0 comments on commit 92f677d

Please sign in to comment.