github.com/elfadel/cilium@v1.6.12/pkg/monitor/logrecord.go (about)

     1  // Copyright 2018 Authors of Cilium
     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 monitor
    16  
    17  import (
    18  	"encoding/json"
    19  	"fmt"
    20  	"strings"
    21  
    22  	"github.com/cilium/cilium/pkg/proxy/accesslog"
    23  	"github.com/miekg/dns"
    24  )
    25  
    26  // LogRecordNotify is a proxy access log notification
    27  type LogRecordNotify struct {
    28  	accesslog.LogRecord
    29  }
    30  
    31  func (l *LogRecordNotify) direction() string {
    32  	switch l.ObservationPoint {
    33  	case accesslog.Ingress:
    34  		return "<-"
    35  	case accesslog.Egress:
    36  		return "->"
    37  	default:
    38  		return "??"
    39  	}
    40  }
    41  
    42  func (l *LogRecordNotify) l7Proto() string {
    43  	if l.HTTP != nil {
    44  		return "http"
    45  	}
    46  
    47  	if l.Kafka != nil {
    48  		return "kafka"
    49  	}
    50  
    51  	if l.DNS != nil {
    52  		return "dns"
    53  	}
    54  
    55  	if l.L7 != nil {
    56  		return l.L7.Proto
    57  	}
    58  
    59  	return "unknown-l7"
    60  }
    61  
    62  // DumpInfo dumps an access log notification
    63  func (l *LogRecordNotify) DumpInfo() {
    64  	switch l.Type {
    65  	case accesslog.TypeRequest:
    66  		fmt.Printf("%s %s %s from %d (%s) to %d (%s), identity %d->%d, verdict %s",
    67  			l.direction(), l.Type, l.l7Proto(), l.SourceEndpoint.ID, l.SourceEndpoint.Labels,
    68  			l.DestinationEndpoint.ID, l.DestinationEndpoint.Labels,
    69  			l.SourceEndpoint.Identity, l.DestinationEndpoint.Identity,
    70  			l.Verdict)
    71  
    72  	case accesslog.TypeResponse:
    73  		fmt.Printf("%s %s %s to %d (%s) from %d (%s), identity %d->%d, verdict %s",
    74  			l.direction(), l.Type, l.l7Proto(), l.SourceEndpoint.ID, l.SourceEndpoint.Labels,
    75  			l.DestinationEndpoint.ID, l.DestinationEndpoint.Labels,
    76  			l.SourceEndpoint.Identity, l.DestinationEndpoint.Identity,
    77  			l.Verdict)
    78  	}
    79  
    80  	if http := l.HTTP; http != nil {
    81  		url := ""
    82  		if http.URL != nil {
    83  			url = http.URL.String()
    84  		}
    85  
    86  		fmt.Printf(" %s %s => %d\n", http.Method, url, http.Code)
    87  	}
    88  
    89  	if kafka := l.Kafka; kafka != nil {
    90  		fmt.Printf(" %s topic %s => %d\n", kafka.APIKey, kafka.Topic.Topic, kafka.ErrorCode)
    91  	}
    92  
    93  	if l.DNS != nil {
    94  		types := []string{}
    95  		for _, t := range l.DNS.QTypes {
    96  			types = append(types, dns.TypeToString[t])
    97  		}
    98  		qTypeStr := strings.Join(types, ",")
    99  
   100  		switch {
   101  		case l.Type == accesslog.TypeRequest:
   102  			fmt.Printf(" DNS Query: %s %s", l.DNS.Query, qTypeStr)
   103  
   104  		case l.Type == accesslog.TypeResponse:
   105  			sourceType := "Query"
   106  			if l.DNS.ObservationSource == accesslog.DNSSourceAgentPoller {
   107  				sourceType = "Poll"
   108  			}
   109  
   110  			fmt.Printf(" DNS %s: %s %s", sourceType, l.DNS.Query, qTypeStr)
   111  
   112  			ips := make([]string, 0, len(l.DNS.IPs))
   113  			for _, ip := range l.DNS.IPs {
   114  				ips = append(ips, ip.String())
   115  			}
   116  			fmt.Printf(" TTL: %d Answer: '%s'", l.DNS.TTL, strings.Join(ips, ","))
   117  
   118  			if len(l.DNS.CNAMEs) > 0 {
   119  				fmt.Printf(" CNAMEs: %s", strings.Join(l.DNS.CNAMEs, ","))
   120  			}
   121  		}
   122  		fmt.Printf("\n")
   123  	}
   124  
   125  	if l7 := l.L7; l7 != nil {
   126  		status := ""
   127  		for k, v := range l7.Fields {
   128  			if k == "status" {
   129  				status = v
   130  			} else {
   131  				fmt.Printf(" %s:%s", k, v)
   132  			}
   133  		}
   134  		if status != "" {
   135  			fmt.Printf(" => status:%s", status)
   136  		}
   137  		fmt.Printf("\n")
   138  	}
   139  }
   140  
   141  func (l *LogRecordNotify) getJSON() (string, error) {
   142  	v := LogRecordNotifyToVerbose(l)
   143  
   144  	ret, err := json.Marshal(v)
   145  	return string(ret), err
   146  }
   147  
   148  // DumpJSON prints notification in json format
   149  func (l *LogRecordNotify) DumpJSON() {
   150  	resp, err := l.getJSON()
   151  	if err == nil {
   152  		fmt.Println(resp)
   153  	}
   154  }
   155  
   156  // LogRecordNotifyVerbose represents a json notification printed by monitor
   157  type LogRecordNotifyVerbose struct {
   158  	Type             string                     `json:"type"`
   159  	ObservationPoint accesslog.ObservationPoint `json:"observationPoint"`
   160  	FlowType         accesslog.FlowType         `json:"flowType"`
   161  	L7Proto          string                     `json:"l7Proto"`
   162  	SrcEpID          uint64                     `json:"srcEpID"`
   163  	SrcEpLabels      []string                   `json:"srcEpLabels"`
   164  	SrcIdentity      uint64                     `json:"srcIdentity"`
   165  	DstEpID          uint64                     `json:"dstEpID"`
   166  	DstEpLabels      []string                   `json:"dstEpLabels"`
   167  	DstIdentity      uint64                     `json:"dstIdentity"`
   168  	Verdict          accesslog.FlowVerdict      `json:"verdict"`
   169  	HTTP             *accesslog.LogRecordHTTP   `json:"http,omitempty"`
   170  	Kafka            *accesslog.LogRecordKafka  `json:"kafka,omitempty"`
   171  	DNS              *accesslog.LogRecordDNS    `json:"dns,omitempty"`
   172  	L7               *accesslog.LogRecordL7     `json:"l7,omitempty"`
   173  }
   174  
   175  // LogRecordNotifyToVerbose turns LogRecordNotify into json-friendly Verbose structure
   176  func LogRecordNotifyToVerbose(n *LogRecordNotify) LogRecordNotifyVerbose {
   177  	return LogRecordNotifyVerbose{
   178  		Type:             "logRecord",
   179  		ObservationPoint: n.ObservationPoint,
   180  		FlowType:         n.Type,
   181  		L7Proto:          n.l7Proto(),
   182  		SrcEpID:          n.SourceEndpoint.ID,
   183  		SrcEpLabels:      n.SourceEndpoint.Labels,
   184  		SrcIdentity:      n.SourceEndpoint.Identity,
   185  		DstEpID:          n.DestinationEndpoint.ID,
   186  		DstEpLabels:      n.DestinationEndpoint.Labels,
   187  		DstIdentity:      n.DestinationEndpoint.Identity,
   188  		Verdict:          n.Verdict,
   189  		HTTP:             n.HTTP,
   190  		Kafka:            n.Kafka,
   191  		DNS:              n.DNS,
   192  		L7:               n.L7,
   193  	}
   194  }