pkg/process/finders/scanner/process.go (90 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 scanner
import (
"fmt"
"strings"
"github.com/shirou/gopsutil/process"
"github.com/apache/skywalking-rover/pkg/process/api"
"github.com/apache/skywalking-rover/pkg/process/finders/base"
"github.com/apache/skywalking-rover/pkg/tools/profiling"
)
type Process struct {
// original reference
original *process.Process
finderConfig *RegexFinder
// process data
pid int32
cmd string
profiling *profiling.Info
// entity for backend
entity *api.ProcessEntity
}
func NewProcessByRegex(p *process.Process, cmdline string, config *RegexFinder) *Process {
stat, _ := base.BuildProfilingStat(p)
return &Process{original: p, pid: p.Pid, cmd: cmdline, finderConfig: config, profiling: stat, entity: &api.ProcessEntity{}}
}
func NewProcessByAgent(p *process.Process, cmdline string, agent *AgentMetadata) (*Process, error) {
// basic data check
var err error
err = requiredNotNull(err, "layer", agent.Layer)
err = requiredNotNull(err, "service name", agent.ServiceName)
err = requiredNotNull(err, "instance name", agent.InstanceName)
err = requiredNotNull(err, "process name", agent.ProcessName)
if err != nil {
return nil, err
}
// labels getter
labels := make([]string, 0)
if agent.Labels != "" {
labels = strings.Split(agent.Labels, ",")
}
// profiling status
stat, _ := base.BuildProfilingStat(p)
// build result
return &Process{
original: p,
pid: p.Pid,
cmd: cmdline,
profiling: stat,
entity: &api.ProcessEntity{
Layer: agent.Layer,
ServiceName: agent.ServiceName,
InstanceName: agent.InstanceName,
ProcessName: agent.ProcessName,
Labels: labels,
},
}, nil
}
func (p *Process) Pid() int32 {
return p.pid
}
func (p *Process) Entity() *api.ProcessEntity {
return p.entity
}
func (p *Process) DetectType() api.ProcessDetectType {
return api.Scanner
}
func (p *Process) OriginalProcess() *process.Process {
return p.original
}
func (p *Process) ProfilingStat() *profiling.Info {
return p.profiling
}
// BuildIdentity without pid
func (p *Process) BuildIdentity() string {
return fmt.Sprintf("%s_%s_%s_%s", p.entity.Layer, p.entity.ServiceName,
p.entity.InstanceName, p.entity.ProcessName)
}
func (p *Process) ExposePorts() []int {
connections, err := p.original.Connections()
if err != nil {
log.Warnf("error getting the process connections, pid: %d, error: %v", p.pid, err)
}
ports := make([]int, 0)
for _, con := range connections {
if con.Status == "LISTEN" {
ports = append(ports, int(con.Laddr.Port))
}
}
return ports
}
func requiredNotNull(err error, key, value string) error {
if err != nil {
return err
}
if value == "" {
return fmt.Errorf("the %s could not be null", key)
}
return nil
}