Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

discovery: add rails service name detector #30091

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -342,9 +342,6 @@ func (s *discovery) getServiceInfo(proc *process.Process) (*serviceInfo, error)
return nil, err
}

contextMap := make(usm.DetectorContextMap)
contextMap[usm.ServiceProc] = proc

root := kernel.HostProc(strconv.Itoa(int(proc.Pid)), "root")
lang := language.FindInArgs(exe, cmdline)
if lang == "" {
Expand All @@ -356,6 +353,8 @@ func (s *discovery) getServiceInfo(proc *process.Process) (*serviceInfo, error)
}

contextMap := make(usm.DetectorContextMap)
contextMap[usm.ServiceProc] = proc

fs := usm.NewSubDirFS(root)
ctx := usm.NewDetectionContext(cmdline, env, fs)
ctx.Pid = int(proc.Pid)
Expand Down
41 changes: 24 additions & 17 deletions pkg/collector/corechecks/servicediscovery/usm/ruby.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.
// Copyright 2024-present Datadog, Inc.

package usm

import (
"fmt"
"io"
"io/fs"
"regexp"
Expand Down Expand Up @@ -35,7 +36,16 @@ func newRailsDetector(ctx DetectionContext) detector {
// project is created. This file should contain a `module` declaration with the
// application name.
func (r railsDetector) detect(_ []string) (ServiceMetadata, bool) {
proc := r.ctx.contextMap[ServiceProc].(*process.Process)
var proc *process.Process

if procEntry, ok := r.ctx.ContextMap[ServiceProc]; ok {
if p, ok := procEntry.(*process.Process); ok {
proc = p
} else {
log.Error("could not get process object in rails detector")
Yumasi marked this conversation as resolved.
Show resolved Hide resolved
}
}

cwd, err := proc.Cwd()
if err != nil {
log.Debugf("could not get cwd of process: %s", err)
Expand All @@ -47,8 +57,9 @@ func (r railsDetector) detect(_ []string) (ServiceMetadata, bool) {
return ServiceMetadata{}, false
}

name, ok := r.findRailsApplicationName(absFile)
if !ok {
name, err := r.findRailsApplicationName(absFile)
if err != nil {
log.Debugf("could not find ruby application name: %s", err)
return ServiceMetadata{}, false
}

Expand All @@ -57,37 +68,33 @@ func (r railsDetector) detect(_ []string) (ServiceMetadata, bool) {

// findRailsApplicationName scans the `config/application.rb` file to find the
// Rails application name.
func (r railsDetector) findRailsApplicationName(filename string) (string, bool) {
log.Debugf("findRailsApplicationName")
func (r railsDetector) findRailsApplicationName(filename string) (string, error) {
file, err := r.ctx.fs.Open(filename)
if err != nil {
log.Debugf("could not open application.rb")
return "", false
return "", fmt.Errorf("could not open application.rb: %w", err)
}
defer file.Close()

reader, err := SizeVerifiedReader(file)
if err != nil {
log.Debugf("skipping application.rb (%q): %v", filename, err)
return "", true
return "", fmt.Errorf("skipping application.rb (%q): %w", filename, err)
}

bytes, err := io.ReadAll(reader)
yuri-lipnesh marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
log.Debugf("unable to read application.rb (%q): %v", filename, err)
return "", true
return "", fmt.Errorf("unable to read application.rb (%q): %w", filename, err)
}

matches := moduleRegexp.FindSubmatch(bytes)
if matches != nil {
return string(matches[1]), true
if len(matches) < 2 {
// No match found
return "", fmt.Errorf("could not find Ruby module name")
Yumasi marked this conversation as resolved.
Show resolved Hide resolved
}

// No match found
return "", false
return string(matches[1]), nil
}

// Converts a PascalCasedWord to a snake_cased_word.
// railsUnderscore converts a PascalCasedWord to a snake_cased_word.
// It keeps uppercase acronyms together when converting (e.g. "HTTPServer" -> "http_server").
func railsUnderscore(pascalCasedWord string) string {
snake := matchFirstCap.ReplaceAllString(pascalCasedWord, "${1}_${2}")
Expand Down
4 changes: 2 additions & 2 deletions pkg/collector/corechecks/servicediscovery/usm/ruby_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.
// Copyright 2024-present Datadog, Inc.

//go:build !windows
//go:build linux

package usm

Expand Down
Loading