apps/oracledb.go (853 lines of code) (raw):

// Copyright 2022 Google LLC // // Licensed 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 apps import ( "context" "fmt" "net/url" "path" "strings" "github.com/GoogleCloudPlatform/ops-agent/confgenerator" "github.com/GoogleCloudPlatform/ops-agent/confgenerator/fluentbit" "github.com/GoogleCloudPlatform/ops-agent/confgenerator/otel" "github.com/GoogleCloudPlatform/ops-agent/internal/secret" ) type MetricsReceiverOracleDB struct { confgenerator.ConfigComponent `yaml:",inline"` confgenerator.MetricsReceiverShared `yaml:",inline"` Insecure *bool `yaml:"insecure" validate:"omitempty"` InsecureSkipVerify *bool `yaml:"insecure_skip_verify" validate:"omitempty"` Endpoint string `yaml:"endpoint" validate:"omitempty,hostname_port|startswith=/"` Username string `yaml:"username"` Password secret.String `yaml:"password"` SID string `yaml:"sid" validate:"omitempty"` ServiceName string `yaml:"service_name" validate:"omitempty"` Wallet string `yaml:"wallet" validate:"omitempty"` } const defaultOracleDBEndpoint = "localhost:1521" func (r MetricsReceiverOracleDB) Type() string { return "oracledb" } func (r MetricsReceiverOracleDB) Pipelines(_ context.Context) ([]otel.ReceiverPipeline, error) { endpoint := r.Endpoint if r.Endpoint == "" { endpoint = defaultOracleDBEndpoint } // put all parameters that are provided to the datasource as query params // in an url.Values so they can be easily encoded params := url.Values{} if r.SID != "" { params.Add("SID", r.SID) } if r.Wallet != "" { params.Add("WALLET", r.Wallet) } if r.Insecure != nil && *r.Insecure == false { params.Add("SSL", "ENABLE") } if r.InsecureSkipVerify != nil && *r.InsecureSkipVerify == false { params.Add("SSL VERIFY", "ENABLE") } if strings.HasPrefix(r.Endpoint, "/") { params.Add("UNIX SOCKET", r.Endpoint) endpoint = defaultOracleDBEndpoint } auth := url.QueryEscape(r.Username) secretPassword := r.Password.SecretValue() if len(secretPassword) > 0 { auth = fmt.Sprintf("%s:%s", auth, url.QueryEscape(secretPassword)) } // create a datasource in the form oracle://username:password@host:port/ServiceName?SID=sid&ssl=enable&... datasource := fmt.Sprintf("oracle://%s@%s/%s?%s", auth, endpoint, url.QueryEscape(r.ServiceName), params.Encode(), ) config := map[string]interface{}{ "collection_interval": r.CollectionIntervalString(), "driver": "oracle", "datasource": datasource, "queries": sqlReceiverQueriesConfig(oracleQueries), } return []otel.ReceiverPipeline{{ Receiver: otel.Component{ Type: "sqlquery", Config: config, }, Processors: map[string][]otel.Component{"metrics": { otel.NormalizeSums(), otel.MetricsTransform( otel.AddPrefix("workload.googleapis.com", // sql query receiver is not able to create these attributes with lowercase names otel.RenameLabel("DATABASE_ID", "database_id"), otel.RenameLabel("GLOBAL_NAME", "global_name"), otel.RenameLabel("INSTANCE_ID", "instance_id"), otel.RenameLabel("TABLESPACE_NAME", "tablespace_name"), otel.RenameLabel("CONTENTS", "contents"), otel.RenameLabel("STATUS", "status"), otel.RenameLabel("PROGRAM", "program"), otel.RenameLabel("WAIT_CLASS", "wait_class"), ), ), otel.ModifyInstrumentationScope(r.Type(), "1.0"), }}, }}, nil } var oracleQueries = []sqlReceiverQuery{ { query: `SELECT (SELECT DBID FROM SYS.GV_$$DATABASE) DATABASE_ID, (SELECT GLOBAL_NAME FROM sys.GLOBAL_NAME) GLOBAL_NAME, ts.TABLESPACE_NAME, ts.CONTENTS, (select sum(df.bytes) from sys.dba_data_files df where df.tablespace_name=ts.tablespace_name)-(select sum(fs.bytes) from sys.dba_free_space fs where fs.tablespace_name=ts.tablespace_name) AS USED_SPACE, (select sum(fs.bytes) from sys.dba_free_space fs where fs.tablespace_name=ts.tablespace_name) AS FREE_SPACE FROM sys.dba_tablespaces ts WHERE ts.contents <> 'TEMPORARY' UNION ALL SELECT (SELECT DBID FROM SYS.GV_$$DATABASE) DATABASE_ID, (SELECT GLOBAL_NAME FROM sys.GLOBAL_NAME) GLOBAL_NAME, ts.NAME TABLESPACE_NAME, 'TEMPORARY' as CONTENTS, SUM(ss.USED_BLOCKS * t.BLOCK_SIZE) USED_SPACE, SUM(t.BYTES) - SUM(ss.USED_BLOCKS * t.BLOCK_SIZE) FREE_SPACE FROM SYS.V_$$sort_segment ss JOIN sys.v_$$tablespace ts ON ss.TABLESPACE_NAME = ts.NAME JOIN sys.v_$$tempfile t ON t.TS# = ss.TS# GROUP BY ts.NAME`, metrics: []sqlReceiverMetric{ { metric_name: "oracle.tablespace.size", value_column: "FREE_SPACE", unit: "by", description: "The size of tablespaces in the database.", data_type: "sum", monotonic: false, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "TABLESPACE_NAME", "CONTENTS"}, static_attributes: map[string]string{ "db.system": "oracle", "state": "free", }, }, { metric_name: "oracle.tablespace.size", value_column: "USED_SPACE", unit: "by", description: "The size of tablespaces in the database.", data_type: "sum", monotonic: false, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "TABLESPACE_NAME", "CONTENTS"}, static_attributes: map[string]string{ "db.system": "oracle", "state": "used", }, }, }, }, { query: "SELECT (SELECT DBID FROM SYS.GV_$$DATABASE) DATABASE_ID, (SELECT GLOBAL_NAME FROM sys.GLOBAL_NAME) GLOBAL_NAME, CONTENTS, STATUS, COUNT(*) COUNT FROM sys.dba_tablespaces GROUP BY STATUS, CONTENTS", metrics: []sqlReceiverMetric{ { metric_name: "oracle.tablespace.count", value_column: "COUNT", unit: "{tablespaces}", description: "The number of tablespaces in the database.", data_type: "sum", monotonic: false, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "STATUS", "CONTENTS"}, static_attributes: map[string]string{ "db.system": "oracle", }, }, }, }, // remove uptime until there is a consistent plan for support // { // query: "SELECT (SELECT DBID FROM SYS.GV_$$DATABASE) DATABASE_ID, (SELECT GLOBAL_NAME FROM sys.GLOBAL_NAME) GLOBAL_NAME, INST_ID INSTANCE_ID, INSTANCE_ROLE, (sysdate - startup_time) * 86400 UPTIME FROM SYS.GV_$$instance", // metrics: []sqlReceiverMetric{ // { // metric_name: "oracle.uptime", // value_column: "UPTIME", // unit: "s", // description: "The number of seconds the instance has been up.", // data_type: "sum", // monotonic: true, // value_type: "int", // attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID", "INSTANCE_ROLE"}, // static_attributes: map[string]string{ // "db.system": "oracle", // }, // }, // }, // }, { query: "SELECT (SELECT DBID FROM SYS.GV_$$DATABASE) DATABASE_ID, (SELECT GLOBAL_NAME FROM sys.GLOBAL_NAME) GLOBAL_NAME, (SELECT round(case when max(start_time) is null then -1 when sysdate - max(start_time) > 0 then (sysdate - max(start_time)) * 86400 else 0 end) FROM SYS.V_$$rman_backup_job_details ) LATEST_BACKUP FROM DUAL", metrics: []sqlReceiverMetric{ { metric_name: "oracle.backup.latest", value_column: "LATEST_BACKUP", unit: "s", description: "The number of seconds since the last RMAN backup.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME"}, static_attributes: map[string]string{ "db.system": "oracle", }, }, }, }, { query: `SELECT DATABASE_ID, GLOBAL_NAME, INST_ID INSTANCE_ID, MAX(PROCESSES_UTIL) PROCESSES_UTIL, MAX(PROCESSES_LIMIT_VAL) PROCESSES_LIMIT_VAL, MAX(SESSIONS_UTIL) SESSIONS_UTIL, MAX(SESSIONS_LIMIT_VAL) SESSIONS_LIMIT_VAL FROM (SELECT (SELECT DBID FROM SYS.GV_$$DATABASE) DATABASE_ID, (SELECT GLOBAL_NAME FROM sys.GLOBAL_NAME) GLOBAL_NAME, INST_ID, PROCESSES_UTIL, PROCESSES_LIMIT_VAL, SESSIONS_UTIL, SESSIONS_LIMIT_VAL FROM (SELECT * FROM SYS.GV_$$resource_limit WHERE RESOURCE_NAME IN ('processes', 'sessions')) PIVOT( MAX(TRIM(CURRENT_UTILIZATION)) UTIL, MAX(TRIM(LIMIT_VALUE)) LIMIT_VAL FOR RESOURCE_NAME IN ( 'processes' PROCESSES, 'sessions' SESSIONS ) ) ) GROUP BY DATABASE_ID, GLOBAL_NAME, INST_ID`, metrics: []sqlReceiverMetric{ { metric_name: "oracle.process.count", value_column: "PROCESSES_UTIL", unit: "{processes}", description: "The current number of processes.", data_type: "sum", monotonic: false, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", }, }, { metric_name: "oracle.process.limit", value_column: "PROCESSES_LIMIT_VAL", unit: "{processes}", description: "The maximum number of processes allowed.", data_type: "sum", monotonic: false, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", }, }, { metric_name: "oracle.session.count", value_column: "SESSIONS_UTIL", unit: "{sessions}", description: "The current number of sessions.", data_type: "sum", monotonic: false, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", }, }, { metric_name: "oracle.session.limit", value_column: "SESSIONS_LIMIT_VAL", unit: "{sessions}", description: "The maximum number of sessions allowed.", data_type: "sum", monotonic: false, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", }, }, }, }, { query: "SELECT (SELECT DBID FROM SYS.GV_$$DATABASE) DATABASE_ID, (SELECT GLOBAL_NAME FROM sys.GLOBAL_NAME) GLOBAL_NAME, INST_ID INSTANCE_ID, PROGRAM, SUM(PGA_USED_MEM) USED_MEM, SUM(PGA_ALLOC_MEM) - SUM(PGA_USED_MEM) FREE_MEM FROM SYS.GV_$$PROCESS WHERE PROGRAM <> 'PSEUDO' GROUP BY PROGRAM, INST_ID", metrics: []sqlReceiverMetric{ { metric_name: "oracle.process.pga_memory.size", value_column: "USED_MEM", unit: "by", description: "The programmable global area memory allocated by process.", data_type: "sum", monotonic: false, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID", "PROGRAM"}, static_attributes: map[string]string{ "db.system": "oracle", "state": "used", }, }, { metric_name: "oracle.process.pga_memory.size", value_column: "FREE_MEM", unit: "by", description: "The programmable global area memory allocated by process.", data_type: "sum", monotonic: false, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID", "PROGRAM"}, static_attributes: map[string]string{ "db.system": "oracle", "state": "free", }, }, }, }, { query: "SELECT (SELECT DBID FROM SYS.GV_$$DATABASE) DATABASE_ID, (SELECT GLOBAL_NAME FROM sys.GLOBAL_NAME) GLOBAL_NAME, INST_ID INSTANCE_ID, WAIT_CLASS, SUM(total_waits_fg) AS TOTAL_WAITS_FG, SUM(total_waits)-SUM(total_waits_fg) AS TOTAL_WAITS_BG, SUM(total_timeouts_fg) AS TOTAL_TIMEOUTS_FG, SUM(total_timeouts)-SUM(TOTAL_TIMEOUTS_FG) AS TOTAL_TIMEOUTS_BG, SUM(time_waited_fg) AS TIME_WAITED_FG, SUM(time_waited)-SUM(TIME_WAITED_FG) AS TIME_WAITED_BG FROM SYS.GV_$$system_event WHERE wait_class <> 'Idle' GROUP BY INST_ID, WAIT_CLASS", metrics: []sqlReceiverMetric{ { metric_name: "oracle.wait.count", value_column: "TOTAL_WAITS_FG", unit: "{events}", description: "The number of wait events experienced.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID", "WAIT_CLASS"}, static_attributes: map[string]string{ "db.system": "oracle", "type": "foreground", }, }, { metric_name: "oracle.wait.count", value_column: "TOTAL_WAITS_BG", unit: "{events}", description: "The number of wait events experienced.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID", "WAIT_CLASS"}, static_attributes: map[string]string{ "db.system": "oracle", "type": "background", }, }, { metric_name: "oracle.wait.time", value_column: "TIME_WAITED_FG", unit: "cs", description: "The amount of time waited for wait events.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID", "WAIT_CLASS"}, static_attributes: map[string]string{ "db.system": "oracle", "type": "foreground", }, }, { metric_name: "oracle.wait.time", value_column: "TIME_WAITED_BG", unit: "cs", description: "The amount of time waited for wait events.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID", "WAIT_CLASS"}, static_attributes: map[string]string{ "db.system": "oracle", "type": "background", }, }, { metric_name: "oracle.wait.timeouts", value_column: "TOTAL_TIMEOUTS_FG", unit: "{timeouts}", description: "The number of timeouts for wait events.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID", "WAIT_CLASS"}, static_attributes: map[string]string{ "db.system": "oracle", "type": "foreground", }, }, { metric_name: "oracle.wait.timeouts", value_column: "TOTAL_TIMEOUTS_BG", unit: "{timeouts}", description: "The number of timeouts for wait events.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID", "WAIT_CLASS"}, static_attributes: map[string]string{ "db.system": "oracle", "type": "background", }, }, }, }, { query: `SELECT DATABASE_ID, GLOBAL_NAME, INST_ID INSTANCE_ID, MAX(RESPONSE_TIME) RESPONSE_TIME, MAX(BUFFER_HIT_RATIO) BUFFER_HIT_RATIO, MAX(ROW_HIT_RATIO) ROW_HIT_RATIO FROM (SELECT (SELECT DBID FROM SYS.GV_$$DATABASE) DATABASE_ID, (SELECT GLOBAL_NAME FROM sys.GLOBAL_NAME) GLOBAL_NAME, INST_ID, END_TIME, RESPONSE_TIME, BUFFER_HIT_RATIO, ROW_HIT_RATIO FROM (SELECT * FROM SYS.GV_$$sysmetric WHERE METRIC_NAME IN ('SQL Service Response Time', 'Buffer Cache Hit Ratio', 'Row Cache Hit Ratio') AND GROUP_ID = 2) PIVOT( MAX(VALUE) FOR METRIC_NAME IN ( 'SQL Service Response Time' RESPONSE_TIME, 'Buffer Cache Hit Ratio' BUFFER_HIT_RATIO, 'Row Cache Hit Ratio' ROW_HIT_RATIO ) ) ) GROUP BY DATABASE_ID, GLOBAL_NAME, INST_ID`, metrics: []sqlReceiverMetric{ { metric_name: "oracle.service.response_time", value_column: "RESPONSE_TIME", unit: "cs", description: "The average sql service response time.", data_type: "gauge", value_type: "double", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", }, }, { metric_name: "oracle.buffer.cache.ratio", value_column: "BUFFER_HIT_RATIO", unit: "%", description: "Ratio of buffer cache hits to requests.", data_type: "gauge", value_type: "double", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", }, }, { metric_name: "oracle.row.cache.ratio", value_column: "ROW_HIT_RATIO", unit: "%", description: "Ratio of row cache hits to requests.", data_type: "gauge", value_type: "double", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", }, }, }, }, { query: `SELECT DATABASE_ID, GLOBAL_NAME, INST_ID INSTANCE_ID, MAX(CURSORS_CUMULATIVE) CURSORS_CUMULATIVE, MAX(CURSORS_CURRENT) CURSORS_CURRENT, MAX(SORTS_MEM) SORTS_MEM, MAX(SORTS_DISK) SORTS_DISK, MAX(SORTS_ROWS) SORTS_ROWS, MAX(READ_TOTAL) READ_TOTAL, MAX(WRITE_TOTAL) WRITE_TOTAL, MAX(READ_TOTAL_BY) READ_TOTAL_BY, MAX(WRITE_TOTAL_BY) WRITE_TOTAL_BY, MAX(LOGONS_CURRENT) LOGONS_CURRENT, MAX(CLIENT_RECV_BY) CLIENT_RECV_BY, MAX(DBLINK_RECV_BY) DBLINK_RECV_BY, MAX(CLIENT_SENT_BY) CLIENT_SENT_BY, MAX(DBLINK_SENT_BY) DBLINK_SENT_BY, MAX(LOGONS_CUMULATIVE) LOGONS_CUMULATIVE, MAX(USER_CALLS) USER_CALLS, MAX(USER_COMMITS) USER_COMMITS, MAX(USER_ROLLBACKS) USER_ROLLBACKS FROM (SELECT (SELECT DBID FROM SYS.GV_$$DATABASE) DATABASE_ID, (SELECT GLOBAL_NAME FROM sys.GLOBAL_NAME) GLOBAL_NAME, INST_ID, CURSORS_CUMULATIVE, CURSORS_CURRENT, SORTS_MEM, SORTS_DISK, SORTS_ROWS, READ_TOTAL, WRITE_TOTAL, READ_TOTAL_BY, WRITE_TOTAL_BY, LOGONS_CURRENT, CLIENT_RECV_BY, DBLINK_RECV_BY, CLIENT_SENT_BY, DBLINK_SENT_BY, LOGONS_CUMULATIVE, USER_CALLS, USER_COMMITS, USER_ROLLBACKS FROM (SELECT * FROM SYS.GV_$$sysstat WHERE NAME IN ('opened cursors cumulative', 'opened cursors current', 'sorts (memory)', 'sorts (disk)', 'sorts (rows)', 'physical read total IO requests', 'physical write total IO requests', 'physical read total bytes', 'physical write total bytes', 'logons current', 'bytes received via SQL*Net from client', 'bytes received via SQL*Net from dblink', 'bytes sent via SQL*Net to client', 'bytes sent via SQL*Net to dblink', 'logons cumulative', 'user calls', 'user commits', 'user rollbacks') ) PIVOT( MAX(VALUE) FOR NAME IN ( 'opened cursors cumulative' CURSORS_CUMULATIVE, 'opened cursors current' CURSORS_CURRENT, 'logons cumulative' LOGONS_CUMULATIVE, 'logons current' LOGONS_CURRENT, 'sorts (memory)' SORTS_MEM, 'sorts (disk)' SORTS_DISK, 'sorts (rows)' SORTS_ROWS, 'physical read total IO requests' READ_TOTAL, 'physical write total IO requests' WRITE_TOTAL, 'physical read total bytes' READ_TOTAL_BY, 'physical write total bytes' WRITE_TOTAL_BY, 'bytes received via SQL*Net from client' CLIENT_RECV_BY, 'bytes received via SQL*Net from dblink' DBLINK_RECV_BY, 'bytes sent via SQL*Net to client' CLIENT_SENT_BY, 'bytes sent via SQL*Net to dblink' DBLINK_SENT_BY, 'user calls' USER_CALLS, 'user commits' USER_COMMITS, 'user rollbacks' USER_ROLLBACKS ) ) ) GROUP BY DATABASE_ID, GLOBAL_NAME, INST_ID`, metrics: []sqlReceiverMetric{ { metric_name: "oracle.cursor.count", value_column: "CURSORS_CUMULATIVE", unit: "{cursors}", description: "The total number of cursors.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", }, }, { metric_name: "oracle.cursor.current", value_column: "CURSORS_CURRENT", unit: "{cursors}", description: "The current number of cursors.", data_type: "sum", monotonic: false, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", }, }, { metric_name: "oracle.logon.count", value_column: "LOGONS_CUMULATIVE", unit: "{logons}", description: "The total number of logons.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", }, }, { metric_name: "oracle.logon.current", value_column: "LOGONS_CURRENT", unit: "{logons}", description: "The current number of logons.", data_type: "sum", monotonic: false, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", }, }, { metric_name: "oracle.sort.count", value_column: "SORTS_MEM", unit: "{sorts}", description: "The total number of sorts.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", "type": "memory", }, }, { metric_name: "oracle.sort.count", value_column: "SORTS_DISK", unit: "{sorts}", description: "The total number of sorts.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", "type": "disk", }, }, { metric_name: "oracle.sort.row.count", value_column: "SORTS_ROWS", unit: "{rows}", description: "The total number of rows sorted.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", }, }, { metric_name: "oracle.disk.operation.count", value_column: "READ_TOTAL", unit: "{operations}", description: "The number of physical disk operations.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", "direction": "read", }, }, { metric_name: "oracle.disk.operation.size", value_column: "READ_TOTAL_BY", unit: "by", description: "The number of bytes affected by physical disk operations.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", "direction": "read", }, }, { metric_name: "oracle.disk.operation.count", value_column: "WRITE_TOTAL", unit: "{operations}", description: "The number of physical disk operations.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", "direction": "write", }, }, { metric_name: "oracle.disk.operation.size", value_column: "WRITE_TOTAL_BY", unit: "by", description: "The number of bytes affected by physical disk operations.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", "direction": "write", }, }, { metric_name: "oracle.network.data", value_column: "CLIENT_RECV_BY", unit: "by", description: "The total number of bytes communicated on the network.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", "target": "client", "direction": "received", }, }, { metric_name: "oracle.network.data", value_column: "CLIENT_SENT_BY", unit: "by", description: "The total number of bytes communicated on the network.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", "target": "client", "direction": "sent", }, }, { metric_name: "oracle.network.data", value_column: "DBLINK_RECV_BY", unit: "by", description: "The total number of bytes communicated on the network.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", "target": "dblink", "direction": "received", }, }, { metric_name: "oracle.network.data", value_column: "DBLINK_SENT_BY", unit: "by", description: "The total number of bytes communicated on the network.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", "target": "dblink", "direction": "sent", }, }, { metric_name: "oracle.user.calls", value_column: "USER_CALLS", unit: "{calls}", description: "The total number of user calls such as login, parse, fetch, or execute.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", }, }, { metric_name: "oracle.user.commits", value_column: "USER_COMMITS", unit: "{commits}", description: "The total number of user transaction commits.", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", }, }, { metric_name: "oracle.user.rollbacks", value_column: "USER_ROLLBACKS", unit: "{rollbacks}", description: "The total number of times users manually issue the ROLLBACK statement or an error occurs during a user's transactions", data_type: "sum", monotonic: true, value_type: "int", attribute_columns: []string{"DATABASE_ID", "GLOBAL_NAME", "INSTANCE_ID"}, static_attributes: map[string]string{ "db.system": "oracle", }, }, }, }, } func init() { confgenerator.MetricsReceiverTypes.RegisterType(func() confgenerator.MetricsReceiver { return &MetricsReceiverOracleDB{} }) } type LoggingProcessorOracleDBAlert struct { confgenerator.ConfigComponent `yaml:",inline"` } func (lr LoggingProcessorOracleDBAlert) Type() string { return "oracledb_alert" } func (lr LoggingProcessorOracleDBAlert) Components(ctx context.Context, tag string, uid string) []fluentbit.Component { components := confgenerator.LoggingProcessorParseMultilineRegex{ LoggingProcessorParseRegexComplex: confgenerator.LoggingProcessorParseRegexComplex{ Parsers: []confgenerator.RegexParser{ { // Sample log: 2021-12-21T10:19:47.339827-05:00 // Thread 1 opened at log sequence 1 // Current log# 1 seq# 1 mem# 0: /u01/oracle/oradata/DB19C/redo01.log // Successful open of redo thread 1 Regex: `^(?<timestamp>\d+-\d+-\d+T\d+:\d+:\d+.\d+(?:[-+]\d+:\d+|Z))\n(?<message>[\s\S]+)`, Parser: confgenerator.ParserShared{ TimeKey: "timestamp", TimeFormat: "%Y-%m-%dT%H:%M:%S.%L%z", }, }, }, }, Rules: []confgenerator.MultilineRule{ { StateName: "start_state", NextState: "cont", Regex: `^\d+-\d+-\d+T\d+:\d+:\d+.\d+(?:[-+]\d+:\d+|Z)`, }, { StateName: "cont", NextState: "cont", Regex: `^(?!\d+-\d+-\d+T\d+:\d+:\d+.\d+(?:[-+]\d+:\d+|Z)).*$`, }, }, }.Components(ctx, tag, uid) severityVal := "ALERT" components = append(components, confgenerator.LoggingProcessorModifyFields{ Fields: map[string]*confgenerator.ModifyField{ "severity": {StaticValue: &severityVal}, InstrumentationSourceLabel: instrumentationSourceValue(lr.Type()), }, }.Components(ctx, tag, uid)...) return components } type LoggingReceiverOracleDBAlert struct { LoggingProcessorOracleDBAlert `yaml:",inline"` ReceiverMixin confgenerator.LoggingReceiverFilesMixin `yaml:",inline" validate:"structonly"` OracleHome string `yaml:"oracle_home,omitempty" validate:"required_without=IncludePaths,excluded_with=IncludePaths"` IncludePaths []string `yaml:"include_paths,omitempty" validate:"required_without=OracleHome,excluded_with=OracleHome"` } func (lr LoggingReceiverOracleDBAlert) Components(ctx context.Context, tag string) []fluentbit.Component { if len(lr.OracleHome) > 0 { lr.IncludePaths = []string{ path.Join(lr.OracleHome, "/diag/rdbms/*/*/trace/alert_*.log"), } } lr.ReceiverMixin.IncludePaths = lr.IncludePaths c := lr.ReceiverMixin.Components(ctx, tag) c = append(c, lr.LoggingProcessorOracleDBAlert.Components(ctx, tag, lr.Type())...) return c } type LoggingProcessorOracleDBAudit struct { confgenerator.ConfigComponent `yaml:",inline"` } func (lr LoggingProcessorOracleDBAudit) Type() string { return "oracledb_audit" } func (lr LoggingProcessorOracleDBAudit) Components(ctx context.Context, tag string, uid string) []fluentbit.Component { components := confgenerator.LoggingProcessorParseMultilineRegex{ LoggingProcessorParseRegexComplex: confgenerator.LoggingProcessorParseRegexComplex{ Parsers: []confgenerator.RegexParser{ { // Sample log: Wed Sep 14 16:18:03 2022 +00:00 // LENGTH : '623' // ACTION :[373] 'select distinct 'ALTER SYSTEM KILL SESSION ''' || stat.sid || ',' || // sess.serial# || // decode(substr(inst.version, 1, 4), // '12.1', ''' immediate ', ''' force timeout 0 ') || // '-- process 73841' // FROM SYS.V$mystat stat, v$session sess, v$instance inst // where stat.sid=sess.sid // union all // select '/' from dual' // DATABASE USER:[1] '/' // PRIVILEGE :[6] 'SYSDBA' // CLIENT USER:[6] 'oracle' // CLIENT TERMINAL:[5] 'pts/1' // STATUS:[1] '0' // DBID:[10] '1643176521' // SESSIONID:[10] '4294967295' // USERHOST:[7] 'oradb19' // CLIENT ADDRESS:[0] '' // ACTION NUMBER:[1] '3' Regex: `^(?<timestamp>\w+\s+\w+\s+\d+\s+\d+:\d+:\d+\s+\d+\s+(?:[-+]\d+:\d+|Z))\n` + `LENGTH\s*:(?:\[\d*\])?\s*'(?<length>.*)'\n` + `ACTION\s*:(?:\[\d*\])?\s*'(?<action>[\s\S]*)'\n` + `DATABASE USER\s*:(?:\[\d*\])?\s*'(?<database_user>.*)'\n` + `PRIVILEGE\s*:(?:\[\d*\])?\s*'(?<privilege>.*)'\n` + `CLIENT USER\s*:(?:\[\d*\])?\s*'(?<client_user>.*)'\n` + `CLIENT TERMINAL\s*:(?:\[\d*\])?\s*'(?<client_terminal>.*)'\n` + `STATUS\s*:(?:\[\d*\])?\s*'(?<status>.*)'\n` + `DBID\s*:(?:\[\d*\])?\s*'(?<dbid>.*)'\n` + `SESSIONID\s*:(?:\[\d*\])?\s*'(?<sessionid>.*)'\n` + `USERHOST\s*:(?:\[\d*\])?\s*'(?<user_host>.*)'\n` + `CLIENT ADDRESS\s*:(?:\[\d*\])?\s*'(?<client_address>.*)'\n` + `ACTION NUMBER\s*:(?:\[\d*\])?\s*'(?<action_number>.*)'\n?`, Parser: confgenerator.ParserShared{ TimeKey: "timestamp", TimeFormat: "%a %b %d %H:%M:%S %Y %z", Types: map[string]string{ "length": "int", "action_number": "int", "dbid": "int", "sessionid": "int", "status": "int", }, }, }, }, }, Rules: []confgenerator.MultilineRule{ { StateName: "start_state", NextState: "cont", Regex: `^\w+ \w+ {1,2}\d+ {1,2}\d+:\d+:\d+ \d+ (?:[-+]\d+:\d+|Z)`, }, { StateName: "cont", NextState: "cont", Regex: `^(?!\w+ \w+ {1,2}\d+ {1,2}\d+:\d+:\d+ \d+ (?:[-+]\d+:\d+|Z)).*$`, }, }, }.Components(ctx, tag, uid) severityVal := "INFO" components = append(components, confgenerator.LoggingProcessorModifyFields{ Fields: map[string]*confgenerator.ModifyField{ "severity": {StaticValue: &severityVal}, InstrumentationSourceLabel: instrumentationSourceValue(lr.Type()), }, }.Components(ctx, tag, uid)...) return components } type LoggingReceiverOracleDBAudit struct { LoggingProcessorOracleDBAudit `yaml:",inline"` ReceiverMixin confgenerator.LoggingReceiverFilesMixin `yaml:",inline" validate:"structonly"` OracleHome string `yaml:"oracle_home,omitempty" validate:"required_without=IncludePaths,excluded_with=IncludePaths"` IncludePaths []string `yaml:"include_paths,omitempty" validate:"required_without=OracleHome,excluded_with=OracleHome"` } func (lr LoggingReceiverOracleDBAudit) Components(ctx context.Context, tag string) []fluentbit.Component { if len(lr.OracleHome) > 0 { lr.IncludePaths = []string{ path.Join(lr.OracleHome, "/admin/*/adump/*.aud"), } } lr.ReceiverMixin.IncludePaths = lr.IncludePaths c := lr.ReceiverMixin.Components(ctx, tag) c = append(c, lr.LoggingProcessorOracleDBAudit.Components(ctx, tag, lr.Type())...) return c } func init() { confgenerator.LoggingReceiverTypes.RegisterType(func() confgenerator.LoggingReceiver { return &LoggingReceiverOracleDBAlert{} }) confgenerator.LoggingProcessorTypes.RegisterType(func() confgenerator.LoggingProcessor { return &LoggingProcessorOracleDBAlert{} }) confgenerator.LoggingReceiverTypes.RegisterType(func() confgenerator.LoggingReceiver { return &LoggingReceiverOracleDBAudit{} }) confgenerator.LoggingProcessorTypes.RegisterType(func() confgenerator.LoggingProcessor { return &LoggingProcessorOracleDBAudit{} }) }