Added external logging package
parent
dbc2793946
commit
6924e9578a
|
@ -1,7 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/projectdiscovery/subfinder/pkg/log"
|
"github.com/projectdiscovery/gologger"
|
||||||
"github.com/projectdiscovery/subfinder/pkg/runner"
|
"github.com/projectdiscovery/subfinder/pkg/runner"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -11,11 +11,11 @@ func main() {
|
||||||
|
|
||||||
runner, err := runner.NewRunner(options)
|
runner, err := runner.NewRunner(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Could not create runner: %s\n", err)
|
gologger.Fatalf("Could not create runner: %s\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = runner.RunEnumeration()
|
err = runner.RunEnumeration()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Could not run enumeration: %s\n", err)
|
gologger.Fatalf("Could not run enumeration: %s\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
// Package log provides a simple layer for leveled logging in go.
|
|
||||||
package log
|
|
173
pkg/log/log.go
173
pkg/log/log.go
|
@ -1,173 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/logrusorgru/aurora"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Level defines all the available levels we can log at
|
|
||||||
type Level int
|
|
||||||
|
|
||||||
// Available logging levels
|
|
||||||
const (
|
|
||||||
Null Level = iota
|
|
||||||
Fatal
|
|
||||||
Silent
|
|
||||||
Label
|
|
||||||
Misc
|
|
||||||
Error
|
|
||||||
Info
|
|
||||||
Warning
|
|
||||||
Verbose
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// UseColors can be used to control coloring of the output
|
|
||||||
UseColors = true
|
|
||||||
// MaxLevel is the maximum level to log at. By default, logging
|
|
||||||
// is done at Info level. Using verbose will display all the errors too,
|
|
||||||
// Using silent will display only the most relevant information.
|
|
||||||
MaxLevel = Info
|
|
||||||
|
|
||||||
labels = map[Level]string{
|
|
||||||
Warning: "WRN",
|
|
||||||
Error: "ERR",
|
|
||||||
Label: "WRN",
|
|
||||||
Fatal: "FTL",
|
|
||||||
Info: "INF",
|
|
||||||
}
|
|
||||||
|
|
||||||
// mutex protects the current logger
|
|
||||||
mutex = &sync.Mutex{}
|
|
||||||
)
|
|
||||||
|
|
||||||
var stringBuilderPool = &sync.Pool{New: func() interface{} {
|
|
||||||
return new(strings.Builder)
|
|
||||||
}}
|
|
||||||
|
|
||||||
// wrap wraps a given label for a message to a logg-able representation.
|
|
||||||
// It checks if colors are specified and what level we are logging at.
|
|
||||||
func wrap(label string, level Level) string {
|
|
||||||
// Check if we are not using colors, if not, return
|
|
||||||
if !UseColors {
|
|
||||||
return label
|
|
||||||
}
|
|
||||||
|
|
||||||
switch level {
|
|
||||||
case Silent:
|
|
||||||
return label
|
|
||||||
case Info, Verbose:
|
|
||||||
return aurora.Blue(label).String()
|
|
||||||
case Fatal:
|
|
||||||
return aurora.Bold(aurora.Red(label)).String()
|
|
||||||
case Error:
|
|
||||||
return aurora.Red(label).String()
|
|
||||||
case Warning, Label:
|
|
||||||
return aurora.Yellow(label).String()
|
|
||||||
default:
|
|
||||||
return label
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getLabel generates a label for a given message, depending on the level
|
|
||||||
// and the label passed.
|
|
||||||
func getLabel(level Level, label string, sb *strings.Builder) {
|
|
||||||
switch level {
|
|
||||||
case Silent, Misc:
|
|
||||||
return
|
|
||||||
case Error, Fatal, Info, Warning, Label:
|
|
||||||
sb.WriteString("[")
|
|
||||||
sb.WriteString(wrap(labels[level], level))
|
|
||||||
sb.WriteString("]")
|
|
||||||
sb.WriteString(" ")
|
|
||||||
return
|
|
||||||
case Verbose:
|
|
||||||
sb.WriteString("[")
|
|
||||||
sb.WriteString(wrap(label, level))
|
|
||||||
sb.WriteString("]")
|
|
||||||
sb.WriteString(" ")
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// log logs the actual message to the screen
|
|
||||||
func log(level Level, label string, format string, args ...interface{}) {
|
|
||||||
// Don't log if the level is null
|
|
||||||
if level == Null {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if level <= MaxLevel {
|
|
||||||
// Build the log message using the string builder pool
|
|
||||||
sb := stringBuilderPool.Get().(*strings.Builder)
|
|
||||||
|
|
||||||
// Get the label and append it to string builder
|
|
||||||
getLabel(level, label, sb)
|
|
||||||
|
|
||||||
message := fmt.Sprintf(format, args...)
|
|
||||||
sb.WriteString(message)
|
|
||||||
|
|
||||||
if strings.HasSuffix(message, "\n") == false {
|
|
||||||
sb.WriteString("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex.Lock()
|
|
||||||
switch level {
|
|
||||||
case Silent:
|
|
||||||
fmt.Fprintf(os.Stdout, sb.String())
|
|
||||||
default:
|
|
||||||
fmt.Fprintf(os.Stderr, sb.String())
|
|
||||||
}
|
|
||||||
mutex.Unlock()
|
|
||||||
|
|
||||||
sb.Reset()
|
|
||||||
stringBuilderPool.Put(sb)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Infof writes a info message on the screen with the default label
|
|
||||||
func Infof(format string, args ...interface{}) {
|
|
||||||
log(Info, "", format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warningf writes a warning message on the screen with the default label
|
|
||||||
func Warningf(format string, args ...interface{}) {
|
|
||||||
log(Warning, "", format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errorf writes an error message on the screen with the default label
|
|
||||||
func Errorf(format string, args ...interface{}) {
|
|
||||||
log(Error, "", format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verbosef writes a verbose message on the screen with a tabel
|
|
||||||
func Verbosef(format string, label string, args ...interface{}) {
|
|
||||||
log(Verbose, label, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Silentf writes a message on the stdout with no label
|
|
||||||
func Silentf(format string, args ...interface{}) {
|
|
||||||
log(Silent, "", format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fatalf exits the program if we encounter a fatal error
|
|
||||||
func Fatalf(format string, args ...interface{}) {
|
|
||||||
log(Fatal, "", format, args...)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Printf prints a string on screen without any extra stuff
|
|
||||||
func Printf(format string, args ...interface{}) {
|
|
||||||
log(Misc, "", format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Labelf prints a string on screen with a label interface
|
|
||||||
func Labelf(format string, args ...interface{}) {
|
|
||||||
log(Label, "", format, args...)
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/logrusorgru/aurora"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGetLabel(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
level Level
|
|
||||||
label string
|
|
||||||
expected string
|
|
||||||
}{
|
|
||||||
{Fatal, "", fmt.Sprintf("[%s] ", aurora.Bold(aurora.Red(labels[Fatal])).String())},
|
|
||||||
{Silent, "hello", ""},
|
|
||||||
{Error, "error", fmt.Sprintf("[%s] ", aurora.Red(labels[Error]).String())},
|
|
||||||
{Info, "", fmt.Sprintf("[%s] ", aurora.Blue(labels[Info]).String())},
|
|
||||||
{Warning, "", fmt.Sprintf("[%s] ", aurora.Yellow(labels[Warning]).String())},
|
|
||||||
{Verbose, "dns", fmt.Sprintf("[%s] ", aurora.Blue("dns").String())},
|
|
||||||
}
|
|
||||||
|
|
||||||
sb := &strings.Builder{}
|
|
||||||
for _, test := range tests {
|
|
||||||
sb.Reset()
|
|
||||||
getLabel(test.level, test.label, sb)
|
|
||||||
data := sb.String()
|
|
||||||
|
|
||||||
assert.Equal(t, data, test.expected, "Expected message and generate message don't match")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/projectdiscovery/subfinder/pkg/log"
|
"github.com/projectdiscovery/gologger"
|
||||||
"github.com/projectdiscovery/subfinder/pkg/subscraping"
|
"github.com/projectdiscovery/subfinder/pkg/subscraping"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ func (a *Agent) EnumerateSubdomains(domain string, keys subscraping.Keys, timeou
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
for source, data := range timeTaken {
|
for source, data := range timeTaken {
|
||||||
log.Verbosef(data, source)
|
gologger.Verbosef(data, source)
|
||||||
}
|
}
|
||||||
|
|
||||||
close(results)
|
close(results)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package runner
|
package runner
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/projectdiscovery/subfinder/pkg/log"
|
"github.com/projectdiscovery/gologger"
|
||||||
"github.com/projectdiscovery/subfinder/pkg/passive"
|
"github.com/projectdiscovery/subfinder/pkg/passive"
|
||||||
"github.com/projectdiscovery/subfinder/pkg/resolve"
|
"github.com/projectdiscovery/subfinder/pkg/resolve"
|
||||||
)
|
)
|
||||||
|
@ -18,19 +18,19 @@ const Version = `2.3.2`
|
||||||
|
|
||||||
// showBanner is used to show the banner to the user
|
// showBanner is used to show the banner to the user
|
||||||
func showBanner() {
|
func showBanner() {
|
||||||
log.Printf("%s\n", banner)
|
gologger.Printf("%s\n", banner)
|
||||||
log.Printf("\t\tprojectdiscovery.io\n\n")
|
gologger.Printf("\t\tprojectdiscovery.io\n\n")
|
||||||
|
|
||||||
log.Labelf("Use with caution. You are responsible for your actions\n")
|
gologger.Labelf("Use with caution. You are responsible for your actions\n")
|
||||||
log.Labelf("Developers assume no liability and are not responsible for any misuse or damage.\n")
|
gologger.Labelf("Developers assume no liability and are not responsible for any misuse or damage.\n")
|
||||||
log.Labelf("By using subfinder, you also agree to the terms of the APIs used.\n\n")
|
gologger.Labelf("By using subfinder, you also agree to the terms of the APIs used.\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalRunTasks runs the normal startup tasks
|
// normalRunTasks runs the normal startup tasks
|
||||||
func (options *Options) normalRunTasks() {
|
func (options *Options) normalRunTasks() {
|
||||||
configFile, err := UnmarshalRead(options.ConfigFile)
|
configFile, err := UnmarshalRead(options.ConfigFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Could not read configuration file %s: %s\n", options.ConfigFile, err)
|
gologger.Fatalf("Could not read configuration file %s: %s\n", options.ConfigFile, err)
|
||||||
}
|
}
|
||||||
options.YAMLConfig = configFile
|
options.YAMLConfig = configFile
|
||||||
}
|
}
|
||||||
|
@ -49,9 +49,9 @@ func (options *Options) firstRunTasks() {
|
||||||
|
|
||||||
err := config.MarshalWrite(options.ConfigFile)
|
err := config.MarshalWrite(options.ConfigFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Could not write configuration file to %s: %s\n", options.ConfigFile, err)
|
gologger.Fatalf("Could not write configuration file to %s: %s\n", options.ConfigFile, err)
|
||||||
}
|
}
|
||||||
options.YAMLConfig = config
|
options.YAMLConfig = config
|
||||||
|
|
||||||
log.Infof("Configuration file saved to %s\n", options.ConfigFile)
|
gologger.Infof("Configuration file saved to %s\n", options.ConfigFile)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,14 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/projectdiscovery/subfinder/pkg/log"
|
"github.com/projectdiscovery/gologger"
|
||||||
"github.com/projectdiscovery/subfinder/pkg/resolve"
|
"github.com/projectdiscovery/subfinder/pkg/resolve"
|
||||||
"github.com/projectdiscovery/subfinder/pkg/subscraping"
|
"github.com/projectdiscovery/subfinder/pkg/subscraping"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EnumerateSingleDomain performs subdomain enumeration against a single domain
|
// EnumerateSingleDomain performs subdomain enumeration against a single domain
|
||||||
func (r *Runner) EnumerateSingleDomain(domain, output string, append bool) error {
|
func (r *Runner) EnumerateSingleDomain(domain, output string, append bool) error {
|
||||||
log.Infof("Enumerating subdomains for %s\n", domain)
|
gologger.Infof("Enumerating subdomains for %s\n", domain)
|
||||||
|
|
||||||
// Get the API keys for sources from the configuration
|
// Get the API keys for sources from the configuration
|
||||||
// and also create the active resolving engine for the domain.
|
// and also create the active resolving engine for the domain.
|
||||||
|
@ -27,7 +27,7 @@ func (r *Runner) EnumerateSingleDomain(domain, output string, append bool) error
|
||||||
err := resolutionPool.InitWildcards(domain)
|
err := resolutionPool.InitWildcards(domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Log the error but don't quit.
|
// Log the error but don't quit.
|
||||||
log.Warningf("Could not get wildcards for domain %s: %s\n", domain, err)
|
gologger.Warningf("Could not get wildcards for domain %s: %s\n", domain, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ func (r *Runner) EnumerateSingleDomain(domain, output string, append bool) error
|
||||||
for result := range passiveResults {
|
for result := range passiveResults {
|
||||||
switch result.Type {
|
switch result.Type {
|
||||||
case subscraping.Error:
|
case subscraping.Error:
|
||||||
log.Warningf("Could not run source %s: %s\n", result.Source, result.Error)
|
gologger.Warningf("Could not run source %s: %s\n", result.Source, result.Error)
|
||||||
case subscraping.Subdomain:
|
case subscraping.Subdomain:
|
||||||
// Validate the subdomain found and remove wildcards from
|
// Validate the subdomain found and remove wildcards from
|
||||||
if !strings.HasSuffix(result.Value, "."+domain) {
|
if !strings.HasSuffix(result.Value, "."+domain) {
|
||||||
|
@ -60,7 +60,7 @@ func (r *Runner) EnumerateSingleDomain(domain, output string, append bool) error
|
||||||
|
|
||||||
// Log the verbose message about the found subdomain and send the
|
// Log the verbose message about the found subdomain and send the
|
||||||
// host for resolution to the resolution pool
|
// host for resolution to the resolution pool
|
||||||
log.Verbosef("%s\n", result.Source, subdomain)
|
gologger.Verbosef("%s\n", result.Source, subdomain)
|
||||||
|
|
||||||
// If the user asked to remove wildcard then send on the resolve
|
// If the user asked to remove wildcard then send on the resolve
|
||||||
// queue. Otherwise, if mode is not verbose print the results on
|
// queue. Otherwise, if mode is not verbose print the results on
|
||||||
|
@ -70,7 +70,7 @@ func (r *Runner) EnumerateSingleDomain(domain, output string, append bool) error
|
||||||
}
|
}
|
||||||
|
|
||||||
if !r.options.Verbose {
|
if !r.options.Verbose {
|
||||||
log.Silentf("%s\n", subdomain)
|
gologger.Silentf("%s\n", subdomain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ func (r *Runner) EnumerateSingleDomain(domain, output string, append bool) error
|
||||||
for result := range resolutionPool.Results {
|
for result := range resolutionPool.Results {
|
||||||
switch result.Type {
|
switch result.Type {
|
||||||
case resolve.Error:
|
case resolve.Error:
|
||||||
log.Warningf("Could not resolve host: %s\n", result.Error)
|
gologger.Warningf("Could not resolve host: %s\n", result.Error)
|
||||||
case resolve.Subdomain:
|
case resolve.Subdomain:
|
||||||
// Add the found subdomain to a map.
|
// Add the found subdomain to a map.
|
||||||
if _, ok := foundResults[result.Host]; !ok {
|
if _, ok := foundResults[result.Host]; !ok {
|
||||||
|
@ -105,11 +105,11 @@ func (r *Runner) EnumerateSingleDomain(domain, output string, append bool) error
|
||||||
if r.options.Verbose {
|
if r.options.Verbose {
|
||||||
if r.options.RemoveWildcard {
|
if r.options.RemoveWildcard {
|
||||||
for result := range foundResults {
|
for result := range foundResults {
|
||||||
log.Silentf("%s\n", result)
|
gologger.Silentf("%s\n", result)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for result := range uniqueMap {
|
for result := range uniqueMap {
|
||||||
log.Silentf("%s\n", result)
|
gologger.Silentf("%s\n", result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ func (r *Runner) EnumerateSingleDomain(domain, output string, append bool) error
|
||||||
file, err = os.Create(output)
|
file, err = os.Create(output)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Could not create file %s for %s: %s\n", output, domain, err)
|
gologger.Errorf("Could not create file %s for %s: %s\n", output, domain, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ func (r *Runner) EnumerateSingleDomain(domain, output string, append bool) error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Could not write results to file %s for %s: %s\n", output, domain, err)
|
gologger.Errorf("Could not write results to file %s for %s: %s\n", output, domain, err)
|
||||||
}
|
}
|
||||||
file.Close()
|
file.Close()
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"github.com/projectdiscovery/subfinder/pkg/log"
|
"github.com/projectdiscovery/gologger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options contains the configuration options for tuning
|
// Options contains the configuration options for tuning
|
||||||
|
@ -42,7 +42,7 @@ func ParseOptions() *Options {
|
||||||
config, err := GetConfigDirectory()
|
config, err := GetConfigDirectory()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// This should never be reached
|
// This should never be reached
|
||||||
log.Fatalf("Could not get user home: %s\n", err)
|
gologger.Fatalf("Could not get user home: %s\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
flag.BoolVar(&options.Verbose, "v", false, "Show Verbose output")
|
flag.BoolVar(&options.Verbose, "v", false, "Show Verbose output")
|
||||||
|
@ -76,7 +76,7 @@ func ParseOptions() *Options {
|
||||||
showBanner()
|
showBanner()
|
||||||
|
|
||||||
if options.Version {
|
if options.Version {
|
||||||
log.Infof("Current Version: %s\n", Version)
|
gologger.Infof("Current Version: %s\n", Version)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ func ParseOptions() *Options {
|
||||||
// invalid options have been used, exit.
|
// invalid options have been used, exit.
|
||||||
err = options.validateOptions()
|
err = options.validateOptions()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Program exiting: %s\n", err)
|
gologger.Fatalf("Program exiting: %s\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return options
|
return options
|
||||||
|
|
|
@ -3,7 +3,7 @@ package runner
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/projectdiscovery/subfinder/pkg/log"
|
"github.com/projectdiscovery/gologger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// validateOptions validates the configuration options passed
|
// validateOptions validates the configuration options passed
|
||||||
|
@ -47,12 +47,12 @@ func (options *Options) validateOptions() error {
|
||||||
func (options *Options) configureOutput() {
|
func (options *Options) configureOutput() {
|
||||||
// If the user desires verbose output, show verbose output
|
// If the user desires verbose output, show verbose output
|
||||||
if options.Verbose {
|
if options.Verbose {
|
||||||
log.MaxLevel = log.Verbose
|
gologger.MaxLevel = gologger.Verbose
|
||||||
}
|
}
|
||||||
if options.NoColor {
|
if options.NoColor {
|
||||||
log.UseColors = false
|
gologger.UseColors = false
|
||||||
}
|
}
|
||||||
if options.Silent {
|
if options.Silent {
|
||||||
log.MaxLevel = log.Silent
|
gologger.MaxLevel = gologger.Silent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue