You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@skywalking.apache.org by wu...@apache.org on 2022/03/01 07:26:10 UTC

[skywalking-rover] branch main updated: Support detect VM level process (#5)

This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-rover.git


The following commit(s) were added to refs/heads/main by this push:
     new 55f11d3  Support detect VM level process (#5)
55f11d3 is described below

commit 55f11d36000dd85d4747f6a7f26661a350d9d11f
Author: mrproliu <74...@qq.com>
AuthorDate: Tue Mar 1 15:19:18 2022 +0800

    Support detect VM level process (#5)
---
 .golangci.yml                                      |   7 +
 configs/rover_configs.yaml                         |  27 +-
 go.mod                                             |   7 +
 go.sum                                             |  17 ++
 pkg/boot/module.go                                 |   5 +
 pkg/boot/module_test.go                            |  39 ++-
 pkg/boot/register.go                               |   2 +
 pkg/config/env_override.go                         |   4 +
 pkg/core/api.go                                    |   2 +
 pkg/core/module.go                                 |  18 +-
 pkg/module/manager_test.go                         |   3 +
 pkg/module/module.go                               |   3 +
 pkg/process/api/process.go                         |  62 ++++
 pkg/{boot/register.go => process/config.go}        |  19 +-
 .../register.go => process/finders/base/config.go} |  13 +-
 pkg/process/finders/base/finder.go                 |  58 ++++
 .../finders/base/process.go}                       |  20 +-
 pkg/process/finders/base/template.go               | 123 ++++++++
 pkg/process/finders/context.go                     |  63 ++++
 pkg/process/finders/manager.go                     | 119 ++++++++
 pkg/{boot => process/finders}/register.go          |  21 +-
 pkg/process/finders/storage.go                     | 242 ++++++++++++++++
 pkg/process/finders/vm/config.go                   |  57 ++++
 pkg/process/finders/vm/finder.go                   | 318 +++++++++++++++++++++
 pkg/process/finders/vm/process.go                  |  67 +++++
 pkg/process/finders/vm/template.go                 |  56 ++++
 pkg/{core/module.go => process/mdoule.go}          |  45 ++-
 pkg/tools/ip.go                                    | 153 ++++++++++
 pkg/tools/process.go                               |  95 ++++++
 pkg/tools/profiling/api.go                         |  64 +++++
 .../register.go => tools/profiling/go_library.go}  |  42 ++-
 pkg/tools/profiling/kernel.go                      |  67 +++++
 pkg/tools/profiling/objdump.go                     |  66 +++++
 33 files changed, 1837 insertions(+), 67 deletions(-)

diff --git a/.golangci.yml b/.golangci.yml
index e7982e4..dd69a2d 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -56,6 +56,13 @@ linters-settings:
   whitespace:
     multi-if: false
     multi-func: false
+  gosec:
+    includes:
+      - G401
+      - G306
+      - G101
+    excludes:
+      - G204
 
 linters:
   enable:
diff --git a/configs/rover_configs.yaml b/configs/rover_configs.yaml
index a1d5591..f46fb82 100644
--- a/configs/rover_configs.yaml
+++ b/configs/rover_configs.yaml
@@ -32,4 +32,29 @@ core:
     # How frequently to check the connection(second)
     check_period: ${ROVER_BACKEND_CHECK_PERIOD:5}
     # The auth value when send request
-    authentication: ${ROVER_BACKEND_AUTHENTICATION:""}
\ No newline at end of file
+    authentication: ${ROVER_BACKEND_AUTHENTICATION:""}
+
+process_discovery:
+  # The period of report or keep alive process(second)
+  heartbeat_period: ${ROVER_PROCESS_DISCOVERY_HEARTBEAT_PERIOD:20s}
+  # Detect processes in VM mode
+  vm:
+    # Is active the VM mode to detect processes
+    active: ${ROVER_PROCESS_DISCOVERY_VM_ACTIVE:false}
+    # The period to detect the process
+    period: ${ROVER_PROCESS_DISCOVERY_VM_PERIOD:3s}
+    finders:
+      # Use regex string to locate the processes
+      # Duplicate entities cannot be reported. If multiple entity are generated, only one process will be report
+      # If the multiple finders could match the same one process, only the first finder could be selected and report
+      - match_cmd_regex: ${ROVER_PROCESS_DISCOVERY_VM_FINDER_MATCH_CMD_REGEX:}
+        # The Layer need to relate to the process entity
+        layer: ${ROVER_PROCESS_DISCOVERY_VM_FINDER_LAYER:VM}
+        # The Service Name need to relate to the process entity
+        service_name: ${ROVER_PROCESS_DISCOVERY_VM_FINDER_SERVICE_NAME:}
+        # The Service Instance Name need to relate to the process entity
+        # By default the instance name is the host IP v4 address from "en0" net interface
+        instance_name: ${ROVER_PROCESS_DISCOVERY_VM_FINDER_INSTANCE_NAME:{{.Rover.HostIPV4 "en0"}}}
+        # The Process Name need to relate to the process entity
+        # By default, the process name is the executable name of the process
+        process_name: ${ROVER_PROCESS_DISCOVERY_VM_FINDER_PROCESS_NAME:{{.Process.ExeName}}}
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 90a2a35..a600bb2 100644
--- a/go.mod
+++ b/go.mod
@@ -3,15 +3,19 @@ module github.com/apache/skywalking-rover
 go 1.17
 
 require (
+	github.com/google/uuid v1.3.0
 	github.com/hashicorp/go-multierror v1.1.1
+	github.com/shirou/gopsutil v3.21.11+incompatible
 	github.com/sirupsen/logrus v1.8.1
 	github.com/spf13/cobra v1.3.0
 	github.com/spf13/viper v1.10.1
 	google.golang.org/grpc v1.44.0
+	skywalking.apache.org/repo/goapi v0.0.0-20220228040118-f1aefbfd2a8c
 )
 
 require (
 	github.com/fsnotify/fsnotify v1.5.1 // indirect
+	github.com/go-ole/go-ole v1.2.6 // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/hashicorp/errwrap v1.0.0 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
@@ -24,6 +28,9 @@ require (
 	github.com/spf13/jwalterweatherman v1.1.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/subosito/gotenv v1.2.0 // indirect
+	github.com/tklauser/go-sysconf v0.3.9 // indirect
+	github.com/tklauser/numcpus v0.3.0 // indirect
+	github.com/yusufpapurcu/wmi v1.2.2 // indirect
 	golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect
 	golang.org/x/sys v0.0.0-20211210111614-af8b64212486 // indirect
 	golang.org/x/text v0.3.7 // indirect
diff --git a/go.sum b/go.sum
index 4748765..ace9634 100644
--- a/go.sum
+++ b/go.sum
@@ -115,6 +115,8 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -188,6 +190,8 @@ github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLe
 github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
@@ -312,6 +316,8 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
 github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
 github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
+github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
@@ -342,12 +348,18 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
+github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
+github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
+github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
+github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
 go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
 go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
 go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs=
@@ -493,6 +505,7 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -536,9 +549,11 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -796,3 +811,5 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+skywalking.apache.org/repo/goapi v0.0.0-20220228040118-f1aefbfd2a8c h1:gf4vxQAHDGBYPpqBsWN5x6+gBCnfzxnI0yPc8acznO8=
+skywalking.apache.org/repo/goapi v0.0.0-20220228040118-f1aefbfd2a8c/go.mod h1:4KrWd+Oi4lkB+PtxZgIlf+3T6EECPru4fOWNMEHjxRk=
diff --git a/pkg/boot/module.go b/pkg/boot/module.go
index db92ad4..a66e4ed 100644
--- a/pkg/boot/module.go
+++ b/pkg/boot/module.go
@@ -91,6 +91,11 @@ func (m *ModuleStarter) Run(ctx context.Context) error {
 		m.startedModules = append(m.startedModules, module)
 	}
 
+	// notify all modules setup success
+	for _, mod := range m.startedModules {
+		mod.NotifyStartSuccess()
+	}
+
 	// register terminal
 	signals := make(chan os.Signal, 1)
 	signal.Notify(signals, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
diff --git a/pkg/boot/module_test.go b/pkg/boot/module_test.go
index cd30e49..a6a89d8 100644
--- a/pkg/boot/module_test.go
+++ b/pkg/boot/module_test.go
@@ -156,6 +156,9 @@ func TestRun(t *testing.T) {
 			startSequence: []string{
 				"test1", "test2",
 			},
+			startNotifySequence: []string{
+				"test1", "test2",
+			},
 			shutdownSequence: []string{
 				"test2", "test1",
 			},
@@ -175,6 +178,9 @@ func TestRun(t *testing.T) {
 			startSequence: []string{
 				"test1", "test2",
 			},
+			startNotifySequence: []string{
+				"test1", "test2",
+			},
 			shutdownSequence: []string{
 				"test2", "test1",
 			},
@@ -194,6 +200,9 @@ func TestRun(t *testing.T) {
 			startSequence: []string{
 				"test2", "test1",
 			},
+			startNotifySequence: []string{
+				"test2", "test1",
+			},
 			shutdownSequence: []string{
 				"test1", "test2",
 			},
@@ -211,12 +220,13 @@ func TestRun(t *testing.T) {
 }
 
 type testRunStruct struct {
-	name             string
-	dependencies     map[string][]string
-	modules          []string
-	startSequence    []string
-	shutdownSequence []string
-	triggerShutdown  func(ctx context.Context, cancel context.CancelFunc, starter *ModuleStarter)
+	name                string
+	dependencies        map[string][]string
+	modules             []string
+	startSequence       []string
+	startNotifySequence []string
+	shutdownSequence    []string
+	triggerShutdown     func(ctx context.Context, cancel context.CancelFunc, starter *ModuleStarter)
 }
 
 func testRun(run *testRunStruct, t *testing.T) {
@@ -265,20 +275,29 @@ func testRun(run *testRunStruct, t *testing.T) {
 		t.Fatalf("the module start sequence not right: \nexcept: \n%v\nactual:\n%v", run.startSequence, sequence.startSequence)
 	}
 
+	if !reflect.DeepEqual(sequence.startNotifySequence, run.startNotifySequence) {
+		t.Fatalf("the module start sequence not right: \nexcept: \n%v\nactual:\n%v", run.startSequence, sequence.startSequence)
+	}
+
 	if !reflect.DeepEqual(sequence.shutdownSequence, run.shutdownSequence) {
 		t.Fatalf("the module shutdown sequence not right: \nexcept: \n%v\nactual:\n%v", run.shutdownSequence, sequence.shutdownSequence)
 	}
 }
 
 type sequenceMonitor struct {
-	startSequence    []string
-	shutdownSequence []string
+	startSequence       []string
+	startNotifySequence []string
+	shutdownSequence    []string
 }
 
 func (s *sequenceMonitor) AddStartup(name string) {
 	s.startSequence = append(s.startSequence, name)
 }
 
+func (s *sequenceMonitor) AddNotifyStart(name string) {
+	s.startNotifySequence = append(s.startNotifySequence, name)
+}
+
 func (s *sequenceMonitor) AddShutdown(name string) {
 	s.shutdownSequence = append(s.shutdownSequence, name)
 }
@@ -306,6 +325,10 @@ func (t *testModule) Start(ctx context.Context, mgr *module.Manager) error {
 	return nil
 }
 
+func (t *testModule) NotifyStartSuccess() {
+	t.sequence.AddNotifyStart(t.name)
+}
+
 func (t *testModule) Shutdown(ctx context.Context, mgr *module.Manager) error {
 	t.sequence.AddShutdown(t.name)
 	return nil
diff --git a/pkg/boot/register.go b/pkg/boot/register.go
index d77d5c2..061cb4a 100644
--- a/pkg/boot/register.go
+++ b/pkg/boot/register.go
@@ -20,9 +20,11 @@ package boot
 import (
 	"github.com/apache/skywalking-rover/pkg/core"
 	"github.com/apache/skywalking-rover/pkg/module"
+	"github.com/apache/skywalking-rover/pkg/process"
 )
 
 func init() {
 	// register all active module
 	module.Register(core.NewModule())
+	module.Register(process.NewModule())
 }
diff --git a/pkg/config/env_override.go b/pkg/config/env_override.go
index e42cdd7..be8a925 100644
--- a/pkg/config/env_override.go
+++ b/pkg/config/env_override.go
@@ -46,6 +46,10 @@ func overrideConfig(v *viper.Viper, key string, envRegex *regexp.Regexp) {
 		v.Set(key, overrideString(val, envRegex))
 	case []interface{}:
 		v.Set(key, overrideSlice(val, envRegex))
+	case int:
+		v.Set(key, val)
+	case bool:
+		v.Set(key, val)
 	}
 }
 
diff --git a/pkg/core/api.go b/pkg/core/api.go
index 7559ccc..a05a33f 100644
--- a/pkg/core/api.go
+++ b/pkg/core/api.go
@@ -21,6 +21,8 @@ import "github.com/apache/skywalking-rover/pkg/core/backend"
 
 // Operator when the other module operate with core module
 type Operator interface {
+	// InstanceId of Rover
+	InstanceID() string
 	// BackendOperator for operate with backend client
 	BackendOperator() backend.Operator
 }
diff --git a/pkg/core/module.go b/pkg/core/module.go
index d044bfa..7670b1a 100644
--- a/pkg/core/module.go
+++ b/pkg/core/module.go
@@ -20,10 +20,12 @@ package core
 import (
 	"context"
 
-	"github.com/apache/skywalking-rover/pkg/core/backend"
-	"github.com/apache/skywalking-rover/pkg/module"
+	"github.com/google/uuid"
 
 	"github.com/hashicorp/go-multierror"
+
+	"github.com/apache/skywalking-rover/pkg/core/backend"
+	"github.com/apache/skywalking-rover/pkg/module"
 )
 
 const ModuleName = "core"
@@ -31,6 +33,7 @@ const ModuleName = "core"
 type Module struct {
 	config *Config
 
+	instanceID    string
 	backendClient *backend.Client
 }
 
@@ -51,6 +54,8 @@ func (m *Module) Config() module.ConfigInterface {
 }
 
 func (m *Module) Start(ctx context.Context, mgr *module.Manager) error {
+	// generate instance id
+	m.instanceID = uuid.New().String()
 	// backend client
 	if m.config.BackendConfig != nil {
 		m.backendClient = backend.NewClient(m.config.BackendConfig)
@@ -61,6 +66,9 @@ func (m *Module) Start(ctx context.Context, mgr *module.Manager) error {
 	return nil
 }
 
+func (m *Module) NotifyStartSuccess() {
+}
+
 func (m *Module) Shutdown(ctx context.Context, mgr *module.Manager) error {
 	var result *multierror.Error
 	if m.backendClient != nil {
@@ -69,9 +77,13 @@ func (m *Module) Shutdown(ctx context.Context, mgr *module.Manager) error {
 	return result.ErrorOrNil()
 }
 
-func (m *Module) ClientGrpcOperator() backend.Operator {
+func (m *Module) BackendOperator() backend.Operator {
 	if m.backendClient == nil {
 		return nil
 	}
 	return m.backendClient
 }
+
+func (m *Module) InstanceID() string {
+	return m.instanceID
+}
diff --git a/pkg/module/manager_test.go b/pkg/module/manager_test.go
index f713944..af7ac7c 100644
--- a/pkg/module/manager_test.go
+++ b/pkg/module/manager_test.go
@@ -71,6 +71,9 @@ func (t *testModule) Start(ctx context.Context, mgr *Manager) error {
 	return nil
 }
 
+func (t *testModule) NotifyStartSuccess() {
+}
+
 func (t *testModule) Shutdown(ctx context.Context, mgr *Manager) error {
 	return nil
 }
diff --git a/pkg/module/module.go b/pkg/module/module.go
index e6f43d6..a97c9ae 100644
--- a/pkg/module/module.go
+++ b/pkg/module/module.go
@@ -37,6 +37,9 @@ type Module interface {
 	// The module needs to return the start result after startup is completed
 	Start(ctx context.Context, mgr *Manager) error
 
+	// NotifyStartSuccess when all module have been start success
+	NotifyStartSuccess()
+
 	// Shutdown module, the sequence of shutdown is the reverse of the module Start
 	// The shutdown would trigger in the following cases
 	// 1. If other modules fail to start
diff --git a/pkg/process/api/process.go b/pkg/process/api/process.go
new file mode 100644
index 0000000..39d5d84
--- /dev/null
+++ b/pkg/process/api/process.go
@@ -0,0 +1,62 @@
+// 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 api
+
+type ProcessDetectType int8
+
+const (
+	_ ProcessDetectType = iota
+	VM
+	KUBERNETES
+)
+
+func (d ProcessDetectType) Name() string {
+	if d == VM {
+		return "VM"
+	} else if d == KUBERNETES {
+		return "Kubernetes"
+	}
+	return "not matched"
+}
+
+type ProcessInterface interface {
+	// ID of process, it's provide by backend
+	ID() string
+	// Pid of process
+	Pid() int32
+	// DetectType of process, it decide how to find this process
+	DetectType() ProcessDetectType
+	// Entity of process in backend
+	Entity() *ProcessEntity
+}
+
+// ProcessEntity is related to backend entity concept
+type ProcessEntity struct {
+	Layer        string
+	ServiceName  string
+	InstanceName string
+	ProcessName  string
+}
+
+func (e *ProcessEntity) SameWith(other *ProcessEntity) bool {
+	if e == nil || other == nil {
+		return false
+	}
+	return e.Layer == other.Layer && e.ServiceName == other.ServiceName && e.InstanceName == other.InstanceName &&
+		e.ProcessName == other.ProcessName
+}
diff --git a/pkg/boot/register.go b/pkg/process/config.go
similarity index 74%
copy from pkg/boot/register.go
copy to pkg/process/config.go
index d77d5c2..36194ca 100644
--- a/pkg/boot/register.go
+++ b/pkg/process/config.go
@@ -15,14 +15,23 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package boot
+package process
 
 import (
-	"github.com/apache/skywalking-rover/pkg/core"
 	"github.com/apache/skywalking-rover/pkg/module"
+	"github.com/apache/skywalking-rover/pkg/process/finders/vm"
 )
 
-func init() {
-	// register all active module
-	module.Register(core.NewModule())
+type Config struct {
+	module.Config
+
+	// heartbeat the process list period
+	HeartbeatPeriod string `mapstructure:"heartbeat_period"`
+
+	// VM process finder
+	VM *vm.Config
+}
+
+func (c *Config) IsActive() bool {
+	return true
 }
diff --git a/pkg/boot/register.go b/pkg/process/finders/base/config.go
similarity index 80%
copy from pkg/boot/register.go
copy to pkg/process/finders/base/config.go
index d77d5c2..cd37580 100644
--- a/pkg/boot/register.go
+++ b/pkg/process/finders/base/config.go
@@ -15,14 +15,9 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package boot
+package base
 
-import (
-	"github.com/apache/skywalking-rover/pkg/core"
-	"github.com/apache/skywalking-rover/pkg/module"
-)
-
-func init() {
-	// register all active module
-	module.Register(core.NewModule())
+type FinderBaseConfig interface {
+	// ActiveFinder to detect process
+	ActiveFinder() bool
 }
diff --git a/pkg/process/finders/base/finder.go b/pkg/process/finders/base/finder.go
new file mode 100644
index 0000000..29733f6
--- /dev/null
+++ b/pkg/process/finders/base/finder.go
@@ -0,0 +1,58 @@
+// 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 base
+
+import (
+	"context"
+
+	v3 "skywalking.apache.org/repo/goapi/collect/ebpf/profiling/process/v3"
+
+	"github.com/apache/skywalking-rover/pkg/module"
+	"github.com/apache/skywalking-rover/pkg/process/api"
+)
+
+type BuildEBPFProcessContext struct {
+	HostIP string
+}
+
+// ProcessFinder is defined how to detect the process and communicate with backend
+type ProcessFinder interface {
+	// Init the finder before Start
+	Init(ctx context.Context, conf FinderBaseConfig, manager ProcessManager) error
+	// Start to detect process
+	Start()
+	// Stop the process detect
+	Stop() error
+	// DetectType of Process is detecting
+	DetectType() api.ProcessDetectType
+
+	// ValidateProcessIsSame between two same finder process
+	ValidateProcessIsSame(p1, p2 DetectedProcess) bool
+
+	// BuildEBPFProcess is transform the process entity as backend protocol data
+	BuildEBPFProcess(ctx *BuildEBPFProcessContext, process DetectedProcess) *v3.EBPFProcessProperties
+	// ParseProcessId is means how to read the process id receive from backend
+	ParseProcessID(process DetectedProcess, downstream *v3.EBPFProcessDownstream) string
+}
+
+// ProcessManager is an API work for help ProcessFinder synchronized process with backend
+type ProcessManager interface {
+	GetModuleManager() *module.Manager
+	// SyncAllProcessInFinder is mean synchronized all processes data from current ProcessFinder
+	SyncAllProcessInFinder(processes []DetectedProcess)
+}
diff --git a/pkg/boot/register.go b/pkg/process/finders/base/process.go
similarity index 64%
copy from pkg/boot/register.go
copy to pkg/process/finders/base/process.go
index d77d5c2..7358bd7 100644
--- a/pkg/boot/register.go
+++ b/pkg/process/finders/base/process.go
@@ -15,14 +15,22 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package boot
+package base
 
 import (
-	"github.com/apache/skywalking-rover/pkg/core"
-	"github.com/apache/skywalking-rover/pkg/module"
+	"github.com/shirou/gopsutil/process"
+
+	"github.com/apache/skywalking-rover/pkg/process/api"
 )
 
-func init() {
-	// register all active module
-	module.Register(core.NewModule())
+// DetectedProcess from the finder
+type DetectedProcess interface {
+	// Pid of process in host
+	Pid() int32
+	// OriginalProcess is works for query the process data
+	OriginalProcess() *process.Process
+	// Entity of process, is related with backend entity
+	Entity() *api.ProcessEntity
+	// DetectType define the process find type
+	DetectType() api.ProcessDetectType
 }
diff --git a/pkg/process/finders/base/template.go b/pkg/process/finders/base/template.go
new file mode 100644
index 0000000..3b30c9b
--- /dev/null
+++ b/pkg/process/finders/base/template.go
@@ -0,0 +1,123 @@
+// 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 base
+
+import (
+	"bytes"
+	"fmt"
+	"text/template"
+
+	"github.com/apache/skywalking-rover/pkg/core"
+	"github.com/apache/skywalking-rover/pkg/module"
+	"github.com/apache/skywalking-rover/pkg/tools"
+)
+
+type TemplateBuilder struct {
+	Name     string
+	Template string
+
+	template *template.Template
+}
+
+func NewTemplateBuilder(name, content string) (*TemplateBuilder, error) {
+	tmpl, err := template.New(name).Parse(content)
+	if err != nil {
+		return nil, fmt.Errorf("failed to parse template for %s, content: %s. reason: %v", name, content, err)
+	}
+	return &TemplateBuilder{Name: name, Template: content, template: tmpl}, nil
+}
+
+func (t *TemplateBuilder) Execute(data interface{}) (string, error) {
+	var r bytes.Buffer
+	if err := t.template.Execute(&r, data); err != nil {
+		return "", err
+	}
+	return r.String(), nil
+}
+
+// NewTemplateRover is generated the Rover context for render
+func NewTemplateRover(manager *module.Manager) *TemplateRover {
+	operator := manager.FindModule(core.ModuleName).(core.Operator)
+	return &TemplateRover{operator.InstanceID()}
+}
+
+// NewTemplateProcess is generated the process context for render
+func NewTemplateProcess(manager *module.Manager, process DetectedProcess) *TemplateProcess {
+	return &TemplateProcess{process}
+}
+
+type TemplateRover struct {
+	instanceID string
+}
+
+// InstanceID of rover
+func (t *TemplateRover) InstanceID() string {
+	return t.instanceID
+}
+
+// HostIPV4 ip v4 address of local machine from appoint net interface name
+func (t *TemplateRover) HostIPV4(name string) (string, error) {
+	v4 := tools.HostIPAddressV4(name)
+	if v4 == "" {
+		return "", fmt.Errorf("could not found the ip v4 address from %s", name)
+	}
+	return v4, nil
+}
+
+// HostIPV6 ip v6 address of local machine from appoint net interface name
+func (t *TemplateRover) HostIPV6(name string) (string, error) {
+	v6 := tools.HostIPAddressV6(name)
+	if v6 == "" {
+		return "", fmt.Errorf("could not found the ip v6 address from %s", name)
+	}
+	return v6, nil
+}
+
+// HostName name of local machine
+func (t *TemplateRover) HostName() string {
+	return tools.Hostname()
+}
+
+type TemplateProcess struct {
+	DetectedProcess
+}
+
+// ExeFilePath Execute file path
+func (p *TemplateProcess) ExeFilePath() (string, error) {
+	return p.OriginalProcess().Exe()
+}
+
+// ExeName Execute file name
+func (p *TemplateProcess) ExeName() (string, error) {
+	return p.OriginalProcess().Name()
+}
+
+// CommandLine command line of process
+func (p *TemplateProcess) CommandLine() (string, error) {
+	return p.OriginalProcess().Cmdline()
+}
+
+// Pid of process
+func (p *TemplateProcess) Pid() int32 {
+	return p.OriginalProcess().Pid
+}
+
+// WorkDir means which directory to run the execute file
+func (p *TemplateProcess) WorkDir() (string, error) {
+	return p.OriginalProcess().Cwd()
+}
diff --git a/pkg/process/finders/context.go b/pkg/process/finders/context.go
new file mode 100644
index 0000000..8a5219b
--- /dev/null
+++ b/pkg/process/finders/context.go
@@ -0,0 +1,63 @@
+// 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 finders
+
+import (
+	"github.com/apache/skywalking-rover/pkg/process/api"
+	"github.com/apache/skywalking-rover/pkg/process/finders/base"
+)
+
+type ProcessUploadStatus int8
+
+const (
+	_ ProcessUploadStatus = iota
+	// NotReport is detected the process, but not report to the backend
+	NotReport
+	// ReportSuccess mean backend has informed, so it could have id
+	ReportSuccess
+	// Ignore by the backend
+	Ignore
+)
+
+type ProcessContext struct {
+	// process ID from backed
+	id string
+
+	// sync with backend status
+	syncStatus ProcessUploadStatus
+
+	// detectProcess from finder
+	detectProcess base.DetectedProcess
+	detectType    api.ProcessDetectType
+}
+
+func (p *ProcessContext) ID() string {
+	return p.id
+}
+
+func (p *ProcessContext) Pid() int32 {
+	return p.detectProcess.Pid()
+}
+
+func (p *ProcessContext) DetectType() api.ProcessDetectType {
+	return p.detectType
+}
+
+func (p *ProcessContext) Entity() *api.ProcessEntity {
+	return p.detectProcess.Entity()
+}
diff --git a/pkg/process/finders/manager.go b/pkg/process/finders/manager.go
new file mode 100644
index 0000000..9c2a597
--- /dev/null
+++ b/pkg/process/finders/manager.go
@@ -0,0 +1,119 @@
+// 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 finders
+
+import (
+	"context"
+	"fmt"
+	"time"
+
+	"github.com/apache/skywalking-rover/pkg/logger"
+
+	"github.com/hashicorp/go-multierror"
+
+	"github.com/apache/skywalking-rover/pkg/module"
+	"github.com/apache/skywalking-rover/pkg/process/api"
+	"github.com/apache/skywalking-rover/pkg/process/finders/base"
+)
+
+var log = logger.GetLogger("process", "finder")
+
+// ProcessManager means Manage all Process
+type ProcessManager struct {
+	moduleManager *module.Manager
+	// finders
+	finders map[base.FinderBaseConfig]base.ProcessFinder
+	// process storage
+	storage *ProcessStorage
+}
+
+type ProcessManagerWithFinder struct {
+	*ProcessManager
+	finderType api.ProcessDetectType
+}
+
+func NewProcessManager(ctx context.Context, moduleManager *module.Manager,
+	reportInterval time.Duration, configs ...base.FinderBaseConfig) (*ProcessManager, error) {
+	// locate all finders
+	confinedFinders := make(map[base.FinderBaseConfig]base.ProcessFinder)
+	fsList := make([]base.ProcessFinder, 0)
+	for _, conf := range configs {
+		if conf == nil || !conf.ActiveFinder() {
+			continue
+		}
+		finder := getFinder(conf)
+		confinedFinders[conf] = finder
+		fsList = append(fsList, finder)
+	}
+	if len(confinedFinders) == 0 {
+		return nil, fmt.Errorf("no process finder found")
+	}
+
+	// start new storage
+	storage, err := NewProcessStorage(ctx, moduleManager, reportInterval, fsList)
+	if err != nil {
+		return nil, err
+	}
+
+	// init all finders
+	manager := &ProcessManager{
+		finders:       confinedFinders,
+		moduleManager: moduleManager,
+		storage:       storage,
+	}
+	for conf, finder := range confinedFinders {
+		processManager := &ProcessManagerWithFinder{ProcessManager: manager, finderType: finder.DetectType()}
+		if err := finder.Init(ctx, conf, processManager); err != nil {
+			return nil, fmt.Errorf("starting %s finder failure: %v", finder.DetectType().Name(), err)
+		}
+	}
+
+	return manager, nil
+}
+
+func (m *ProcessManager) Start() {
+	// start all finders
+	for _, finder := range m.finders {
+		finder.Start()
+	}
+	// start storage report with interval
+	m.storage.StartReport()
+}
+
+func (m *ProcessManager) Shutdown() error {
+	var result error
+	// stop reporter
+	if err := m.storage.StopReport(); err != nil {
+		result = multierror.Append(result, err)
+	}
+	// stop finders
+	for _, finder := range m.finders {
+		if err := finder.Stop(); err != nil {
+			result = multierror.Append(result, err)
+		}
+	}
+	return result
+}
+
+func (p *ProcessManagerWithFinder) GetModuleManager() *module.Manager {
+	return p.moduleManager
+}
+
+func (p *ProcessManagerWithFinder) SyncAllProcessInFinder(processes []base.DetectedProcess) {
+	p.storage.SyncAllProcessInFinder(p.finderType, processes)
+}
diff --git a/pkg/boot/register.go b/pkg/process/finders/register.go
similarity index 64%
copy from pkg/boot/register.go
copy to pkg/process/finders/register.go
index d77d5c2..4f63bb8 100644
--- a/pkg/boot/register.go
+++ b/pkg/process/finders/register.go
@@ -15,14 +15,25 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package boot
+package finders
 
 import (
-	"github.com/apache/skywalking-rover/pkg/core"
-	"github.com/apache/skywalking-rover/pkg/module"
+	"reflect"
+
+	"github.com/apache/skywalking-rover/pkg/process/finders/base"
+	"github.com/apache/skywalking-rover/pkg/process/finders/vm"
 )
 
+var finders = make(map[reflect.Type]base.ProcessFinder)
+
 func init() {
-	// register all active module
-	module.Register(core.NewModule())
+	registerFinder(reflect.TypeOf(&vm.Config{}), &vm.ProcessFinder{})
+}
+
+func registerFinder(t reflect.Type, finder base.ProcessFinder) {
+	finders[t] = finder
+}
+
+func getFinder(conf base.FinderBaseConfig) base.ProcessFinder {
+	return finders[reflect.TypeOf(conf)]
 }
diff --git a/pkg/process/finders/storage.go b/pkg/process/finders/storage.go
new file mode 100644
index 0000000..da9c5c8
--- /dev/null
+++ b/pkg/process/finders/storage.go
@@ -0,0 +1,242 @@
+// 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 finders
+
+import (
+	"context"
+	"sync"
+	"time"
+
+	"github.com/hashicorp/go-multierror"
+
+	v3 "skywalking.apache.org/repo/goapi/collect/ebpf/profiling/process/v3"
+
+	"github.com/apache/skywalking-rover/pkg/core"
+	"github.com/apache/skywalking-rover/pkg/module"
+	"github.com/apache/skywalking-rover/pkg/process/api"
+	"github.com/apache/skywalking-rover/pkg/process/finders/base"
+	"github.com/apache/skywalking-rover/pkg/tools"
+)
+
+type ProcessStorage struct {
+	processes map[int32]*ProcessContext
+	mutex     sync.Mutex
+
+	// working with backend
+	reportInterval time.Duration
+	roverID        string
+	processClient  v3.EBPFProcessServiceClient
+	finders        map[api.ProcessDetectType]base.ProcessFinder
+
+	// report context
+	ctx    context.Context
+	cancel context.CancelFunc
+}
+
+func NewProcessStorage(ctx context.Context, moduleManager *module.Manager,
+	reportInterval time.Duration, finderList []base.ProcessFinder) (*ProcessStorage, error) {
+	data := make(map[int32]*ProcessContext)
+	// working with core module
+	coreOperator := moduleManager.FindModule(core.ModuleName).(core.Operator)
+	roverID := coreOperator.InstanceID()
+	backendConn := coreOperator.BackendOperator().GetConnection()
+	processClient := v3.NewEBPFProcessServiceClient(backendConn)
+	ctx, cancel := context.WithCancel(ctx)
+	fs := make(map[api.ProcessDetectType]base.ProcessFinder)
+	for _, f := range finderList {
+		fs[f.DetectType()] = f
+	}
+	return &ProcessStorage{
+		processes:      data,
+		reportInterval: reportInterval,
+		roverID:        roverID,
+		processClient:  processClient,
+		finders:        fs,
+		ctx:            ctx,
+		cancel:         cancel,
+	}, nil
+}
+
+func (s *ProcessStorage) StartReport() {
+	go func() {
+		timeTicker := time.NewTicker(s.reportInterval)
+		for {
+			select {
+			case <-timeTicker.C:
+				if err := s.reportAllProcesses(); err != nil {
+					log.Errorf("report all processes error: %v", err)
+				}
+			case <-s.ctx.Done():
+				timeTicker.Stop()
+				return
+			}
+		}
+	}()
+}
+
+func (s *ProcessStorage) StopReport() error {
+	s.cancel()
+	return nil
+}
+
+func (s *ProcessStorage) reportAllProcesses() error {
+	s.mutex.Lock()
+	defer s.mutex.Unlock()
+	if len(s.processes) == 0 {
+		return nil
+	}
+
+	// build process list(wait report or keep alive)
+	waitReportProcesses := make([]*ProcessContext, 0)
+	keepAliveProcesses := make([]*ProcessContext, 0)
+	for _, p := range s.processes {
+		if p.syncStatus == NotReport {
+			waitReportProcesses = append(waitReportProcesses, p)
+		} else if p.syncStatus == ReportSuccess {
+			keepAliveProcesses = append(keepAliveProcesses, p)
+		}
+	}
+
+	// process with backend
+	var result error
+	if err := s.processesReport(waitReportProcesses); err != nil {
+		result = multierror.Append(result, err)
+	}
+	if err := s.processesKeepAlive(keepAliveProcesses); err != nil {
+		result = multierror.Append(result, err)
+	}
+
+	return result
+}
+
+func (s *ProcessStorage) processesKeepAlive(waitKeepAliveProcess []*ProcessContext) error {
+	if len(waitKeepAliveProcess) == 0 {
+		return nil
+	}
+
+	processIDList := make([]*v3.EBPFProcessPingPkg, 0)
+	for _, ps := range waitKeepAliveProcess {
+		if ps.id != "" {
+			processIDList = append(processIDList, &v3.EBPFProcessPingPkg{ProcessId: ps.id})
+		}
+	}
+
+	_, err := s.processClient.KeepAlive(s.ctx, &v3.EBPFProcessPingPkgList{Processes: processIDList})
+	return err
+}
+
+func (s *ProcessStorage) processesReport(waitReportProcesses []*ProcessContext) error {
+	if len(waitReportProcesses) == 0 {
+		return nil
+	}
+
+	properties := make([]*v3.EBPFProcessProperties, 0)
+	buildContext := &base.BuildEBPFProcessContext{}
+	buildContext.HostIP = tools.DefaultHostIPAddress()
+	for _, ps := range waitReportProcesses {
+		properties = append(properties, s.finders[ps.DetectType()].BuildEBPFProcess(buildContext, ps.detectProcess))
+	}
+	processes, err := s.processClient.ReportProcesses(s.ctx, &v3.EBPFProcessReportList{Processes: properties})
+	if err != nil {
+		return err
+	}
+
+	for _, waitProcess := range waitReportProcesses {
+		found := false
+		for _, reportedProcess := range processes.GetProcesses() {
+			id := s.finders[waitProcess.DetectType()].ParseProcessID(waitProcess.detectProcess, reportedProcess)
+			if id == "" {
+				continue
+			}
+
+			s.updateProcessToUploadSuccess(waitProcess, id)
+			found = true
+			break
+		}
+
+		if !found {
+			s.updateProcessToUploadIgnored(waitProcess)
+		}
+	}
+	return nil
+}
+
+func (s *ProcessStorage) SyncAllProcessInFinder(finder api.ProcessDetectType, processes []base.DetectedProcess) {
+	s.mutex.Lock()
+	defer s.mutex.Unlock()
+
+	pidToProcess := make(map[int32]base.DetectedProcess)
+	for _, ps := range processes {
+		pidToProcess[ps.Pid()] = ps
+	}
+
+	// for each all process in the manager
+	for pid, managedProcess := range s.processes {
+		needToSyncProcess := pidToProcess[pid]
+		// remove it from the list of need to sync
+		pidToProcess[pid] = nil
+
+		// The process to be synchronized is not found in all process list
+		// And this process is same with finder type
+		// So we need to remove this process
+		if needToSyncProcess == nil {
+			if managedProcess.DetectType() == finder {
+				s.processes[pid] = nil
+			}
+			continue
+		}
+
+		// they are the not same detect type
+		// TODO we just implement the VM mode process for now, so continue
+		if needToSyncProcess.DetectType() != managedProcess.DetectType() {
+			continue
+		}
+
+		// check the entity is the same
+		if s.finders[needToSyncProcess.DetectType()].ValidateProcessIsSame(needToSyncProcess, managedProcess.detectProcess) {
+			continue
+		}
+
+		// different entity, so we need to remove oldest and add the new process
+		s.processes[pid] = s.constructNewProcessContext(finder, needToSyncProcess)
+	}
+
+	// other processes are need to be added
+	for pid, ps := range pidToProcess {
+		if ps != nil {
+			s.processes[pid] = s.constructNewProcessContext(finder, ps)
+		}
+	}
+}
+
+func (s *ProcessStorage) constructNewProcessContext(finder api.ProcessDetectType, process base.DetectedProcess) *ProcessContext {
+	return &ProcessContext{
+		syncStatus:    NotReport,
+		detectProcess: process,
+		detectType:    finder,
+	}
+}
+
+func (s *ProcessStorage) updateProcessToUploadSuccess(pc *ProcessContext, id string) {
+	pc.id = id
+	pc.syncStatus = ReportSuccess
+}
+
+func (s *ProcessStorage) updateProcessToUploadIgnored(pc *ProcessContext) {
+	pc.syncStatus = Ignore
+}
diff --git a/pkg/process/finders/vm/config.go b/pkg/process/finders/vm/config.go
new file mode 100644
index 0000000..d1174b1
--- /dev/null
+++ b/pkg/process/finders/vm/config.go
@@ -0,0 +1,57 @@
+// 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 vm
+
+import (
+	"regexp"
+
+	"github.com/apache/skywalking-rover/pkg/process/finders/base"
+)
+
+type Config struct {
+	base.FinderBaseConfig
+
+	Active bool `mapstructure:"active"`
+
+	// Check Period
+	Period string `mapstructure:"period"`
+
+	// Process finder list
+	Finders []*ProcessFinderConfig `mapstructure:"finders"`
+}
+
+func (c *Config) ActiveFinder() bool {
+	return c.Active
+}
+
+type ProcessFinderConfig struct {
+	// Use command line to match the processes
+	MatchCommandRegex string `mapstructure:"match_cmd_regex"`
+
+	// entity
+	Layer        string `mapstructure:"layer"`         // process layer
+	ServiceName  string `mapstructure:"service_name"`  // process entity service name
+	InstanceName string `mapstructure:"instance_name"` // process entity service instance name
+	ProcessName  string `mapstructure:"process_name"`  // process entity process name
+
+	// pre-build for build the process
+	commandlineRegex    *regexp.Regexp
+	serviceNameBuilder  *base.TemplateBuilder
+	instanceNameBuilder *base.TemplateBuilder
+	processNameBuilder  *base.TemplateBuilder
+}
diff --git a/pkg/process/finders/vm/finder.go b/pkg/process/finders/vm/finder.go
new file mode 100644
index 0000000..1f275a8
--- /dev/null
+++ b/pkg/process/finders/vm/finder.go
@@ -0,0 +1,318 @@
+// 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 vm
+
+import (
+	"context"
+	"fmt"
+	"regexp"
+	"time"
+
+	v3 "skywalking.apache.org/repo/goapi/collect/ebpf/profiling/process/v3"
+
+	"github.com/shirou/gopsutil/process"
+
+	"github.com/apache/skywalking-rover/pkg/logger"
+	"github.com/apache/skywalking-rover/pkg/process/api"
+	"github.com/apache/skywalking-rover/pkg/process/finders/base"
+	"github.com/apache/skywalking-rover/pkg/tools"
+)
+
+var log = logger.GetLogger("process", "finder", "vm")
+
+type ProcessFinder struct {
+	conf *Config
+
+	manager   base.ProcessManager
+	ctx       context.Context
+	cancelCtx context.CancelFunc
+
+	period time.Duration
+}
+
+func (p *ProcessFinder) Init(ctx context.Context, conf base.FinderBaseConfig, manager base.ProcessManager) error {
+	if err := validateConfig(conf.(*Config)); err != nil {
+		return err
+	}
+
+	p.conf = conf.(*Config)
+	p.manager = manager
+	p.ctx, p.cancelCtx = context.WithCancel(ctx)
+
+	period, err := time.ParseDuration(p.conf.Period)
+	if err != nil {
+		return err
+	}
+	p.period = period
+	return nil
+}
+
+func (p *ProcessFinder) Start() {
+	go p.startWatch()
+}
+
+func (p *ProcessFinder) Stop() error {
+	p.cancelCtx()
+	return nil
+}
+
+func (p *ProcessFinder) DetectType() api.ProcessDetectType {
+	return api.VM
+}
+
+func (p *ProcessFinder) ValidateProcessIsSame(p1, p2 base.DetectedProcess) bool {
+	vm1 := p1.(*Process)
+	vm2 := p2.(*Process)
+	return p1.Pid() == p2.Pid() && vm1.cmd == vm2.cmd && p1.Entity().SameWith(p2.Entity())
+}
+
+func (p *ProcessFinder) BuildEBPFProcess(ctx *base.BuildEBPFProcessContext, ps base.DetectedProcess) *v3.EBPFProcessProperties {
+	hostProcess := &v3.EBPFHostProcessMetadata{}
+	hostProcess.HostIP = ctx.HostIP
+	hostProcess.Pid = ps.Pid()
+	hostProcess.Cmd = ps.(*Process).cmd
+	hostProcess.Entity = &v3.EBPFProcessEntityMetadata{
+		Layer:        ps.Entity().Layer,
+		ServiceName:  ps.Entity().ServiceName,
+		InstanceName: ps.Entity().InstanceName,
+		ProcessName:  ps.Entity().ProcessName,
+	}
+	properties := &v3.EBPFProcessProperties{Metadata: &v3.EBPFProcessProperties_HostProcess{
+		HostProcess: hostProcess,
+	}}
+	return properties
+}
+
+func (p *ProcessFinder) ParseProcessID(ps base.DetectedProcess, downstream *v3.EBPFProcessDownstream) string {
+	if downstream.GetHostProcess() == nil {
+		return ""
+	}
+	if ps.Pid() == downstream.GetHostProcess().GetPid() {
+		return downstream.ProcessId
+	}
+	return ""
+}
+
+func (p *ProcessFinder) startWatch() {
+	// find one time
+	if err := p.findAndReportProcesses(); err != nil {
+		log.Warnf("list all process failure, %v", err)
+	}
+	// schedule
+	ticker := time.NewTicker(p.period)
+	for {
+		select {
+		case <-ticker.C:
+			if err := p.findAndReportProcesses(); err != nil {
+				log.Warnf("list all process failure, %v", err)
+			}
+		case <-p.ctx.Done():
+			return
+		}
+	}
+}
+
+func (p *ProcessFinder) findAndReportProcesses() error {
+	// find all process
+	processes, err := p.findMatchedProcesses()
+	if err != nil {
+		return err
+	}
+
+	// validate the process could be profiling
+	processes = p.validateTheProcessesCouldProfiling(processes)
+
+	// report to the manager
+	psList := make([]base.DetectedProcess, 0)
+	for _, ps := range processes {
+		psList = append(psList, ps)
+	}
+	p.manager.SyncAllProcessInFinder(psList)
+	return nil
+}
+
+func (p *ProcessFinder) validateTheProcessesCouldProfiling(processes []*Process) []*Process {
+	result := make([]*Process, 0)
+	for _, ps := range processes {
+		exe, err := ps.original.Exe()
+		if err != nil {
+			log.Warnf("could not read process exe file path, pid: %d, reason: %v", ps.pid, err)
+			continue
+		}
+
+		// check support profiling
+		if pf, err := tools.ExecutableFileProfilingStat(exe); err != nil {
+			log.Warnf("the process could not be profiling, so ignored. pid: %d, reason: %v", ps.pid, err)
+			continue
+		} else {
+			ps.profiling = pf
+		}
+
+		result = append(result, ps)
+	}
+	return result
+}
+
+func (p *ProcessFinder) findMatchedProcesses() ([]*Process, error) {
+	// all system processes
+	processes, err := process.ProcessesWithContext(p.ctx)
+	if err != nil {
+		return nil, err
+	}
+	// find all matches processes
+	findedProcesses := make([]*Process, 0)
+	for _, pro := range processes {
+		// TODO should we need verify the process must be in the root namespace? such as exclude the container processes
+		// That's mean the same process would could only be detect by one finder?
+
+		// find the matched process finder
+		finderConfig, cmdline, err := p.findMatchesFinder(pro)
+		if err != nil {
+			log.Warnf("failed to match process %d, reason: %v", pro.Pid, err)
+			continue
+		}
+		if finderConfig == nil {
+			continue
+		}
+
+		// build the linux process and add to the list
+		ps := NewProcess(pro, cmdline, finderConfig)
+		ps.entity.Layer = finderConfig.Layer
+		ps.entity.ServiceName, err = p.buildEntity(err, ps, finderConfig.serviceNameBuilder)
+		ps.entity.InstanceName, err = p.buildEntity(err, ps, finderConfig.instanceNameBuilder)
+		ps.entity.ProcessName, err = p.buildEntity(err, ps, finderConfig.processNameBuilder)
+		if err != nil {
+			log.Warnf("failed to build the process data for pid: %d, reason: %v", pro.Pid, err)
+			continue
+		} else {
+			findedProcesses = append(findedProcesses, ps)
+		}
+	}
+	if len(findedProcesses) == 0 {
+		return nil, nil
+	}
+	// remove duplicated(identity) process
+	identity2Processes := make(map[string][]*Process)
+	for _, ps := range findedProcesses {
+		id := ps.BuildIdentity()
+		if identity2Processes[id] == nil {
+			identity2Processes[id] = make([]*Process, 0)
+		}
+		identity2Processes[id] = append(identity2Processes[id], ps)
+	}
+	result := make([]*Process, 0)
+	for _, psList := range identity2Processes {
+		reportProcess := psList[0]
+		if len(psList) > 1 {
+			pidList := make([]int32, 0)
+			for _, ps := range psList {
+				pidList = append(pidList, ps.pid)
+			}
+			log.WithField("command_line", reportProcess.cmd).
+				WithField("service_name", reportProcess.entity.ServiceName).
+				WithField("instance_name", reportProcess.entity.InstanceName).
+				WithField("process_name", reportProcess.entity.ProcessName).
+				WithField("pid_list", pidList).
+				Warnf("find multiple similar process in VM, " +
+					"only report the first of these processes. " +
+					"please update the name of process to identity them more clear.")
+		}
+		result = append(result, reportProcess)
+	}
+	return result, nil
+}
+
+func (p *ProcessFinder) buildEntity(err error, ps *Process, entity *base.TemplateBuilder) (string, error) {
+	if err != nil {
+		return "", err
+	}
+	return renderTemplate(entity, ps, p)
+}
+
+func (p *ProcessFinder) findMatchesFinder(ps *process.Process) (*ProcessFinderConfig, string, error) {
+	// verify the process exists, if not exists just return
+	if exists, err := process.PidExists(ps.Pid); err != nil {
+		return nil, "", err
+	} else if !exists {
+		return nil, "", nil
+	}
+
+	cmdline, err := ps.Cmdline()
+	if err != nil {
+		return nil, "", fmt.Errorf("query command line failure: %v", err)
+	}
+	var matched *ProcessFinderConfig
+	for _, finder := range p.conf.Finders {
+		if finder.commandlineRegex.MatchString(cmdline) {
+			if matched == nil {
+				matched = finder
+			} else {
+				log.Warnf("found multiple finder for the process %d, command line: %s, choose the first one mached to build process",
+					ps.Pid, cmdline)
+				return matched, cmdline, nil
+			}
+		}
+	}
+	return matched, cmdline, nil
+}
+
+func validateConfig(conf *Config) error {
+	if len(conf.Finders) == 0 {
+		return fmt.Errorf("must have one VM process finder")
+	}
+
+	// validate config
+	for _, f := range conf.Finders {
+		var err error
+		err = stringMustNotNull(err, "layer", f.Layer)
+		f.commandlineRegex, err = regexMustNotNull(err, "match_cmd_regex", f.MatchCommandRegex)
+		f.serviceNameBuilder, err = templateMustNotNull(err, "service_name", f.ServiceName)
+		f.instanceNameBuilder, err = templateMustNotNull(err, "instance_name", f.InstanceName)
+		f.processNameBuilder, err = templateMustNotNull(err, "process_name", f.ProcessName)
+
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func stringMustNotNull(err error, confKey, confValue string) error {
+	if err != nil {
+		return err
+	}
+	if confValue == "" {
+		return fmt.Errorf("the %s of VM process must be set", confKey)
+	}
+	return nil
+}
+
+func templateMustNotNull(err error, confKey, confValue string) (*base.TemplateBuilder, error) {
+	if err1 := stringMustNotNull(err, confKey, confValue); err1 != nil {
+		return nil, err1
+	}
+	return base.NewTemplateBuilder(confKey, confValue)
+}
+
+func regexMustNotNull(err error, confKey, confValue string) (*regexp.Regexp, error) {
+	if err1 := stringMustNotNull(err, confKey, confValue); err1 != nil {
+		return nil, err1
+	}
+	return regexp.Compile(confValue)
+}
diff --git a/pkg/process/finders/vm/process.go b/pkg/process/finders/vm/process.go
new file mode 100644
index 0000000..0973f1a
--- /dev/null
+++ b/pkg/process/finders/vm/process.go
@@ -0,0 +1,67 @@
+// 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 vm
+
+import (
+	"fmt"
+
+	"github.com/shirou/gopsutil/process"
+
+	"github.com/apache/skywalking-rover/pkg/process/api"
+	"github.com/apache/skywalking-rover/pkg/tools/profiling"
+)
+
+type Process struct {
+	// original reference
+	original     *process.Process
+	finderConfig *ProcessFinderConfig
+
+	// process data
+	pid       int32
+	cmd       string
+	profiling *profiling.Info
+
+	// entity for backend
+	entity *api.ProcessEntity
+}
+
+func NewProcess(p *process.Process, cmdline string, config *ProcessFinderConfig) *Process {
+	return &Process{original: p, pid: p.Pid, cmd: cmdline, finderConfig: config, entity: &api.ProcessEntity{}}
+}
+
+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.VM
+}
+
+func (p *Process) OriginalProcess() *process.Process {
+	return p.original
+}
+
+// BuildIdentity without pid
+func (p *Process) BuildIdentity() string {
+	return fmt.Sprintf("%s_%s_%s_%s", p.cmd, p.entity.ServiceName,
+		p.entity.InstanceName, p.entity.ProcessName)
+}
diff --git a/pkg/process/finders/vm/template.go b/pkg/process/finders/vm/template.go
new file mode 100644
index 0000000..7268421
--- /dev/null
+++ b/pkg/process/finders/vm/template.go
@@ -0,0 +1,56 @@
+// 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 vm
+
+import (
+	"fmt"
+
+	"github.com/apache/skywalking-rover/pkg/process/finders/base"
+)
+
+func renderTemplate(builder *base.TemplateBuilder, process *Process, finder *ProcessFinder) (string, error) {
+	moduleManager := finder.manager.GetModuleManager()
+	return builder.Execute(&TemplateContext{
+		Rover:   base.NewTemplateRover(moduleManager),
+		Process: base.NewTemplateProcess(moduleManager, process),
+		Finder:  &TemplateFinder{finder: finder, process: process},
+	})
+}
+
+type TemplateContext struct {
+	Rover   *base.TemplateRover
+	Process *base.TemplateProcess
+	Finder  *TemplateFinder
+}
+
+type TemplateFinder struct {
+	finder  *ProcessFinder
+	process *Process
+}
+
+func (t *TemplateFinder) Layer() string {
+	return t.process.finderConfig.Layer
+}
+
+func (t *TemplateFinder) RegexMatchGroup(inx int) (string, error) {
+	submatch := t.process.finderConfig.commandlineRegex.FindStringSubmatch(t.process.cmd)
+	if len(submatch) == 0 || inx+1 >= len(submatch) {
+		return "", fmt.Errorf("could not find match")
+	}
+	return submatch[inx], nil
+}
diff --git a/pkg/core/module.go b/pkg/process/mdoule.go
similarity index 68%
copy from pkg/core/module.go
copy to pkg/process/mdoule.go
index d044bfa..e7463c7 100644
--- a/pkg/core/module.go
+++ b/pkg/process/mdoule.go
@@ -15,23 +15,23 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package core
+package process
 
 import (
 	"context"
+	"time"
 
-	"github.com/apache/skywalking-rover/pkg/core/backend"
+	"github.com/apache/skywalking-rover/pkg/core"
 	"github.com/apache/skywalking-rover/pkg/module"
-
-	"github.com/hashicorp/go-multierror"
+	"github.com/apache/skywalking-rover/pkg/process/finders"
 )
 
-const ModuleName = "core"
+const ModuleName = "process_discovery"
 
 type Module struct {
 	config *Config
 
-	backendClient *backend.Client
+	manager *finders.ProcessManager
 }
 
 func NewModule() *Module {
@@ -43,7 +43,7 @@ func (m *Module) Name() string {
 }
 
 func (m *Module) RequiredModules() []string {
-	return nil
+	return []string{core.ModuleName}
 }
 
 func (m *Module) Config() module.ConfigInterface {
@@ -51,27 +51,24 @@ func (m *Module) Config() module.ConfigInterface {
 }
 
 func (m *Module) Start(ctx context.Context, mgr *module.Manager) error {
-	// backend client
-	if m.config.BackendConfig != nil {
-		m.backendClient = backend.NewClient(m.config.BackendConfig)
-		if err := m.backendClient.Start(ctx); err != nil {
-			return err
-		}
+	period, err := time.ParseDuration(m.config.HeartbeatPeriod)
+	if err != nil {
+		return err
 	}
+	processManager, err := finders.NewProcessManager(ctx, mgr, period, m.config.VM)
+	if err != nil {
+		return err
+	}
+	m.manager = processManager
+
 	return nil
 }
 
-func (m *Module) Shutdown(ctx context.Context, mgr *module.Manager) error {
-	var result *multierror.Error
-	if m.backendClient != nil {
-		result = multierror.Append(result, m.backendClient.Stop())
-	}
-	return result.ErrorOrNil()
+func (m *Module) NotifyStartSuccess() {
+	// notify all finder to report processes
+	m.manager.Start()
 }
 
-func (m *Module) ClientGrpcOperator() backend.Operator {
-	if m.backendClient == nil {
-		return nil
-	}
-	return m.backendClient
+func (m *Module) Shutdown(ctx context.Context, mgr *module.Manager) error {
+	return m.manager.Shutdown()
 }
diff --git a/pkg/tools/ip.go b/pkg/tools/ip.go
new file mode 100644
index 0000000..b8e5718
--- /dev/null
+++ b/pkg/tools/ip.go
@@ -0,0 +1,153 @@
+// 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 tools
+
+import (
+	"fmt"
+	"net"
+	"os"
+)
+
+var (
+	host *hostInfo
+)
+
+func init() {
+	host = queryHostInfo()
+}
+
+// DefaultHostIPAddress IP address of machine
+func DefaultHostIPAddress() string {
+	return host.defaultIPAddr
+}
+
+// HostIPAddressV4 found the IPV4 address from appoint net interface name
+func HostIPAddressV4(name string) string {
+	address := host.ipAddresses[name]
+	if address == nil {
+		return ""
+	}
+	return address.ipV4
+}
+
+// HostIPAddressV6 found the IPV6 address from appoint net interface name
+func HostIPAddressV6(name string) string {
+	address := host.ipAddresses[name]
+	if address == nil {
+		return ""
+	}
+	return address.ipV6
+}
+
+// Hostname of machine
+func Hostname() string {
+	return host.name
+}
+
+type hostInfo struct {
+	// hostname
+	name string
+	// ip address
+	ipAddresses   map[string]*hostIPAddress
+	defaultIPAddr string
+}
+
+type hostIPAddress struct {
+	ipV4 string
+	ipV6 string
+}
+
+func queryHostInfo() *hostInfo {
+	addresses, def, err := localIPAddress0()
+	if err != nil {
+		panic(err)
+	}
+	name, err := hostname0()
+	if err != nil {
+		panic(err)
+	}
+	return &hostInfo{name: name, ipAddresses: addresses, defaultIPAddr: def}
+}
+
+func hostname0() (string, error) {
+	return os.Hostname()
+}
+
+func localIPAddress0() (ipAddresses map[string]*hostIPAddress, defAddr string, err error) {
+	ifaces, err := net.Interfaces()
+	if err != nil {
+		return nil, "", err
+	}
+	// handle err
+	ipAddresses = make(map[string]*hostIPAddress)
+	var defV4, defV6 string
+	for _, i := range ifaces {
+		if i.Flags&net.FlagLoopback != 0 {
+			continue
+		}
+		addrs, err := i.Addrs()
+		if err != nil {
+			return nil, "", err
+		}
+		ipv4, ipv6 := analyzeIPAddresses(addrs)
+
+		if ipv4 != "" || ipv6 != "" {
+			if defV4 == "" {
+				defV4 = ipv4
+			}
+			if defV6 == "" {
+				defV6 = ipv6
+			}
+			ipAddresses[i.Name] = &hostIPAddress{ipV4: ipv4, ipV6: ipv6}
+		}
+	}
+
+	if len(ipAddresses) == 0 {
+		return nil, "", fmt.Errorf("not found")
+	}
+
+	if defV4 != "" {
+		defAddr = defV4
+	} else {
+		defAddr = defV6
+	}
+
+	return ipAddresses, defAddr, nil
+}
+
+func analyzeIPAddresses(addrs []net.Addr) (ipv4, ipv6 string) {
+	for _, addr := range addrs {
+		var ip net.IP
+		switch v := addr.(type) {
+		case *net.IPNet:
+			ip = v.IP
+		case *net.IPAddr:
+			ip = v.IP
+		}
+		if ip.IsLoopback() {
+			continue
+		}
+		if ip.To4() != nil {
+			ipv4 = ip.To4().String()
+		}
+		if ip.To16() != nil {
+			ipv6 = ip.To16().String()
+		}
+	}
+	return ipv4, ipv6
+}
diff --git a/pkg/tools/process.go b/pkg/tools/process.go
new file mode 100644
index 0000000..46910ff
--- /dev/null
+++ b/pkg/tools/process.go
@@ -0,0 +1,95 @@
+// 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 tools
+
+import (
+	"fmt"
+	"os"
+	"sort"
+	"strings"
+
+	"github.com/apache/skywalking-rover/pkg/tools/profiling"
+)
+
+var (
+	// NotSupportProfilingExe mean which program are not support for profiling
+	// Not Support JIT and Script language for now
+	NotSupportProfilingExe = []string{
+		"java", "python", "node", "bash", "ruby", "ssh",
+	}
+
+	// executable file profiling finders
+	profilingStatFinderList = []profiling.StatFinder{
+		profiling.NewGoLibrary(), profiling.NewObjDump(),
+	}
+
+	// kernel profiling finder
+	kernelFinder = profiling.NewKernelFinder()
+)
+
+// KernelFileProfilingStat is works for read the kernel and get is support for kernel symbol analyze
+func KernelFileProfilingStat() (*profiling.Info, error) {
+	if !kernelFinder.IsSupport(profiling.KernelSymbolFilePath) {
+		return nil, fmt.Errorf("not support kernel space profiling")
+	}
+	return kernelFinder.Analyze(profiling.KernelSymbolFilePath)
+}
+
+// ExecutableFileProfilingStat is validating the exe file could be profiling and get info
+func ExecutableFileProfilingStat(exePath string) (*profiling.Info, error) {
+	stat, err := os.Stat(exePath)
+	if err != nil {
+		return nil, fmt.Errorf("check file error: %v", err)
+	}
+	for _, notSupport := range NotSupportProfilingExe {
+		if strings.HasPrefix(stat.Name(), notSupport) {
+			return nil, fmt.Errorf("not support %s language profiling", notSupport)
+		}
+	}
+
+	var lastError error
+	for _, finder := range profilingStatFinderList {
+		if finder.IsSupport(exePath) {
+			if r, err1 := analyzeByFinder(exePath, finder); err1 == nil {
+				return r, nil
+			}
+			lastError = err
+		}
+	}
+
+	if lastError == nil {
+		lastError = fmt.Errorf("could not found library to analyze the file")
+	}
+
+	return nil, lastError
+}
+
+func analyzeByFinder(exePath string, finder profiling.StatFinder) (*profiling.Info, error) {
+	// do analyze
+	info, err := finder.Analyze(exePath)
+	if err != nil {
+		return nil, err
+	}
+
+	// order the symbols by address
+	sort.SliceStable(info.Symbols, func(i, j int) bool {
+		return info.Symbols[i].Location < info.Symbols[j].Location
+	})
+
+	return info, nil
+}
diff --git a/pkg/tools/profiling/api.go b/pkg/tools/profiling/api.go
new file mode 100644
index 0000000..512fe6d
--- /dev/null
+++ b/pkg/tools/profiling/api.go
@@ -0,0 +1,64 @@
+// 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 profiling
+
+var KernelSymbolFilePath = "/proc/kallsyms"
+
+// Info of profiling process
+type Info struct {
+	Symbols []*Symbol
+}
+
+// Symbol of executable file
+type Symbol struct {
+	Name     string
+	Location uint64
+}
+
+type StatFinder interface {
+	// IsSupport to stat the executable file for profiling
+	IsSupport(filePath string) bool
+	// Analyze the executable file
+	Analyze(filePath string) (*Info, error)
+}
+
+// FindSymbolName by address
+func (i *Info) FindSymbolName(address uint64) string {
+	symbols := i.Symbols
+
+	start := 0
+	end := len(symbols)
+	for start < end {
+		mid := start + (end-start)/2
+		result := int64(address) - int64(symbols[mid].Location)
+
+		if result < 0 {
+			end = mid
+		} else if result > 0 {
+			start = mid + 1
+		} else {
+			return symbols[mid].Name
+		}
+	}
+
+	if start >= 1 && symbols[start-1].Location < address && address < symbols[start].Location {
+		return symbols[start-1].Name
+	}
+
+	return ""
+}
diff --git a/pkg/boot/register.go b/pkg/tools/profiling/go_library.go
similarity index 50%
copy from pkg/boot/register.go
copy to pkg/tools/profiling/go_library.go
index d77d5c2..c5cd3d2 100644
--- a/pkg/boot/register.go
+++ b/pkg/tools/profiling/go_library.go
@@ -15,14 +15,44 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package boot
+package profiling
 
 import (
-	"github.com/apache/skywalking-rover/pkg/core"
-	"github.com/apache/skywalking-rover/pkg/module"
+	"debug/elf"
+	"fmt"
 )
 
-func init() {
-	// register all active module
-	module.Register(core.NewModule())
+// GoLibrary is using build-in elf reader to read
+type GoLibrary struct {
+}
+
+func NewGoLibrary() *GoLibrary {
+	return &GoLibrary{}
+}
+
+func (l *GoLibrary) IsSupport(filePath string) bool {
+	return true
+}
+
+func (l *GoLibrary) Analyze(filePath string) (*Info, error) {
+	// read els file
+	file, err := elf.Open(filePath)
+	if err != nil {
+		return nil, fmt.Errorf("read ELF file error: %v", err)
+	}
+	defer file.Close()
+
+	// exist symbol data
+	symbols, err := file.Symbols()
+	if err != nil || len(symbols) == 0 {
+		return nil, fmt.Errorf("read symbol data failure or no symbole data: %v", err)
+	}
+
+	// adapt symbol struct
+	data := make([]*Symbol, len(symbols))
+	for i, sym := range symbols {
+		data[i] = &Symbol{Name: sym.Name, Location: sym.Value}
+	}
+
+	return &Info{Symbols: data}, nil
 }
diff --git a/pkg/tools/profiling/kernel.go b/pkg/tools/profiling/kernel.go
new file mode 100644
index 0000000..3285463
--- /dev/null
+++ b/pkg/tools/profiling/kernel.go
@@ -0,0 +1,67 @@
+// 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 profiling
+
+import (
+	"bufio"
+	"fmt"
+	"os"
+	"strconv"
+	"strings"
+)
+
+type KernelFinder struct {
+	kernelFileExists bool
+}
+
+func NewKernelFinder() *KernelFinder {
+	stat, _ := os.Stat(KernelSymbolFilePath)
+	return &KernelFinder{kernelFileExists: stat != nil}
+}
+
+func (k *KernelFinder) IsSupport(filepath string) bool {
+	if filepath != KernelSymbolFilePath {
+		return false
+	}
+	stat, _ := os.Stat(filepath)
+	return stat != nil
+}
+
+func (k *KernelFinder) Analyze(filepath string) (*Info, error) {
+	kernelPath, err := os.Open(filepath)
+	if err != nil {
+		return nil, err
+	}
+
+	scanner := bufio.NewScanner(kernelPath)
+	symbols := make([]*Symbol, 0)
+	for scanner.Scan() {
+		info := strings.Split(scanner.Text(), " ")
+		atoi, err := strconv.ParseUint(info[0], 16, 64)
+
+		if err != nil {
+			return nil, fmt.Errorf("error read addr: %s, %v", info[0], err)
+		}
+		symbols = append(symbols, &Symbol{
+			Name:     info[2],
+			Location: atoi,
+		})
+	}
+
+	return &Info{Symbols: symbols}, nil
+}
diff --git a/pkg/tools/profiling/objdump.go b/pkg/tools/profiling/objdump.go
new file mode 100644
index 0000000..4783760
--- /dev/null
+++ b/pkg/tools/profiling/objdump.go
@@ -0,0 +1,66 @@
+// 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 profiling
+
+import (
+	"bufio"
+	"bytes"
+	"os/exec"
+	"regexp"
+	"strconv"
+)
+
+var objDumpOutputFormat = "^([0-9a-f]+)\\s+\\w?\\s+\\w?\\s+\\S+\\s*[0-9a-f]*\\s+(\\S+)$"
+
+// ObjDump is using `objdump` command to read
+type ObjDump struct {
+	commandPath string
+	outputRegex *regexp.Regexp
+}
+
+func NewObjDump() *ObjDump {
+	path, _ := exec.LookPath("objdump")
+	compile := regexp.MustCompile(objDumpOutputFormat)
+	return &ObjDump{commandPath: path, outputRegex: compile}
+}
+
+func (o *ObjDump) IsSupport(filepath string) bool {
+	return o.commandPath != ""
+}
+
+func (o *ObjDump) Analyze(filepath string) (*Info, error) {
+	resBytes, err := exec.Command(o.commandPath, "--syms", filepath).Output() // #nosec G204
+	if err != nil {
+		return nil, err
+	}
+
+	symbols := make([]*Symbol, 0)
+	scanner := bufio.NewScanner(bytes.NewReader(resBytes))
+	for scanner.Scan() {
+		submatch := o.outputRegex.FindStringSubmatch(scanner.Text())
+		if len(submatch) == 0 {
+			continue
+		}
+		atoi, err := strconv.ParseUint(submatch[1], 16, 64)
+		if err != nil {
+			continue
+		}
+		symbols = append(symbols, &Symbol{Name: submatch[2], Location: atoi})
+	}
+	return &Info{Symbols: symbols}, nil
+}