pkg/profiling/continuous/checker/bpf/network/http1.go (99 lines of code) (raw):

// Licensed to Apache Software Foundation (ASF) under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright // ownership. Apache Software Foundation (ASF) licenses this file to you under // the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package network import ( "fmt" "strconv" "strings" "time" "github.com/apache/skywalking-rover/pkg/tools/host" ) type HTTP1BufferEvent struct { pid uint32 requestURI string requestTime uint64 statusCode int responseTime uint64 } type HTTP1Analyzer struct { channelEvents map[uint64]*HTTP1BufferEvent } func NewHTTP1Analyzer() *HTTP1Analyzer { return &HTTP1Analyzer{ channelEvents: make(map[uint64]*HTTP1BufferEvent), } } func (h *HTTP1Analyzer) HandleBufferEvent(buffer *networkBufferInBPF) BufferEvent { if buffer.Direction == BufferDirectionRequest { event := &HTTP1BufferEvent{} event.pid = buffer.Pid event.requestTime = buffer.Timestamp uri, err := h.analyzeRequestURI(buffer) if err != nil { log.Warnf("cannot fount the request uri from content: %s, reason: %v", buffer.Buffer[0:buffer.Size], err) return nil } event.requestURI = uri h.channelEvents[buffer.ChannelRef] = event return nil } event := h.channelEvents[buffer.ChannelRef] // cannot found the last request event if event == nil { return nil } // clean the request buffer delete(h.channelEvents, buffer.ChannelRef) code, err := h.analyzeResponseStatus(buffer) if err != nil { log.Warnf("failure to parse the response status code: content: %s, reason: %v", buffer.Buffer[0:buffer.Size], err) return nil } event.statusCode = code event.responseTime = buffer.Timestamp return event } func (h *HTTP1Analyzer) analyzeRequestURI(buffer *networkBufferInBPF) (string, error) { bufferData := string(buffer.Buffer[0:buffer.Size]) firstSpace := strings.Index(bufferData, " ") if firstSpace <= 0 { return "", fmt.Errorf("the reuquest buffer is not validate") } if len(bufferData) <= firstSpace+1 { return "", fmt.Errorf("current package data data is not enough") } requestURIData := bufferData[firstSpace+1:] for inx, d := range requestURIData { // find the first requestURI end index if d == '?' || d == ' ' { return requestURIData[0:inx], nil } } return "", fmt.Errorf("cannot found the request URI") } func (h *HTTP1Analyzer) analyzeResponseStatus(buffer *networkBufferInBPF) (int, error) { bufferData := string(buffer.Buffer[0:buffer.Size]) firstSpace := strings.Index(bufferData, " ") if firstSpace <= 0 { return 0, fmt.Errorf("the reuquest buffer is not validate") } if len(bufferData) <= firstSpace+1 { return 0, fmt.Errorf("current package data data is not enough") } secondSpace := strings.Index(bufferData[firstSpace+1:], " ") i, err := strconv.ParseInt(bufferData[firstSpace+1:][0:secondSpace], 10, 32) if err != nil { return 0, fmt.Errorf("parse response status error") } return int(i), nil } func (h *HTTP1BufferEvent) StartTime() time.Time { return host.Time(h.requestTime) } func (h *HTTP1BufferEvent) Pid() int32 { return int32(h.pid) } func (h *HTTP1BufferEvent) RequestURI() string { return h.requestURI } func (h *HTTP1BufferEvent) IsResponseError() bool { return h.statusCode >= 500 } func (h *HTTP1BufferEvent) Duration() time.Duration { return time.Duration(h.responseTime - h.requestTime) }