Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[oracle] adding integration #45

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ env:
- DD_AGENT_BRANCH=master
matrix:
- TRAVIS_FLAVOR=default
- TRAVIS_FLAVOR=oracle FLAVOR_VERSION=latest
# END OF TRAVIS MATRIX

before_install:
Expand Down
1 change: 1 addition & 0 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ test:
override:
- bundle exec rake prep_travis_ci
- rake ci:run[default]
- rake ci:run[oracle]
- bundle exec rake requirements
post:
- if [[ $(docker ps -a -q) ]]; then docker stop $(docker ps -a -q); fi
32 changes: 32 additions & 0 deletions oracle/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Oracle Integration

## Overview

Get metrics from oracle service in real time to:

* Visualize and monitor oracle states
* Be notified about oracle failovers and events.

## Installation

Install the `dd-check-oracle` package manually or with your favorite configuration manager

## Configuration

Edit the `oracle.yaml` file to point to your server and port, set the masters to monitor

## Validation

When you run `datadog-agent info` you should see something like the following:

Checks
======

oracle
-----------
- instance #0 [OK]
- Collected 39 metrics, 0 events & 7 service checks

## Compatibility

The oracle check is compatible with all major platforms
109 changes: 109 additions & 0 deletions oracle/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# (C) Datadog, Inc. 2010-2016
# All rights reserved
# Licensed under Simplified BSD License (see LICENSE)

# stdlib

# 3rd party

import cx_Oracle

# project
from checks import AgentCheck

EVENT_TYPE = SOURCE_TYPE_NAME = 'oracle'


class OracleCheck(AgentCheck):

SERVICE_CHECK_NAME = 'oracle.can_connect'
SYS_METRICS = {
'Buffer Cache Hit Ratio': 'oracle.buffer_cachehit_ratio',
'Cursor Cache Hit Ratio': 'oracle.cursor_cachehit_ratio',
'Library Cache Hit Ratio': 'oracle.library_cachehit_ratio',
'Shared Pool Free %': 'oracle.shared_pool_free',
'Physical Reads Per Sec': 'oracle.physical_reads',
'Physical Writes Per Sec': 'oracle.physical_writes',
'Enqueue Timeouts Per Sec': 'oracle.enqueue_timeouts',
'GC CR Block Received Per Second': 'oracle.gc_cr_receive_time',
'Global Cache Blocks Corrupted': 'oracle.cache_blocks_corrupt',
'Global Cache Blocks Lost': 'oracle.cache_blocks_lost',
'Logons Per Sec': 'oracle.logons',
'Average Active Sessions': 'oracle.active_sessions',
'Long Table Scans Per Sec': 'oracle.long_table_scans',
'SQL Service Response Time': 'oracle.service_response_time',
'User Rollbacks Per Sec': 'oracle.user_rollbacks',
'Total Sorts Per User Call': 'oracle.sorts_per_user_call',
'Rows Per Sort': 'oracle.rows_per_sort',
'Disk Sort Per Sec': 'oracle.disk_sorts',
'Memory Sorts Ratio': 'oracle.memroy_sorts_ratio',
'Database Wait Time Ratio': 'oracle.database_wait_time_ratio',
'Enqueue Timeouts Per Sec': 'oracle.enqueue_timeouts',
'Session Limit %': 'oracle.session_limit_usage',
'Session Count': 'oracle.session_count',
'Temp Space Used': 'oracle.temp_space_used',
}

def __init__(self, name, init_config, agentConfig, instances=None):
AgentCheck.__init__(self, name, init_config, agentConfig, instances)

def check(self, instance):
self.log.debug('Running cx_Oracle version {0}'.format(cx_Oracle.version))
server, user, password, tags = self._get_config(instance)

if not server or not user:
raise Exception("Oracle host and user are needed")

con = self._get_connection(server, user, password)

self._get_sys_metrics(con, tags)

self._get_tablespace_metrics(con)

def _get_config(self, instance):
self.server = instance.get('server', None)
user = instance.get('user', None)
password = instance.get('password', None)
tags = instance.get('tags', None)
return (self.server, user, password, tags)

def _get_connection(self, server, user, password):
self.service_check_tags = [
'server:%s' % server
]
connect_string = '{0}/{1}@{2}'.format(user, password, server)
try:
con = cx_Oracle.connect(connect_string)
self.log.debug("Connected to Oracle DB")
self.service_check(self.SERVICE_CHECK_NAME, AgentCheck.OK,
tags=self.service_check_tags)
except Exception, e:
self.service_check(self.SERVICE_CHECK_NAME, AgentCheck.CRITICAL,
tags=self.service_check_tags)
self.log.error(e)
raise
return con

def _get_sys_metrics(self, con, tags):
query = "SELECT METRIC_NAME, VALUE, BEGIN_TIME FROM GV$SYSMETRIC " \
"ORDER BY BEGIN_TIME"
cur = con.cursor()
cur.execute(query)
for row in cur:
metric_name = row[0]
metric_value = row[1]
if metric_name in self.SYS_METRICS:
self.gauge(self.SYS_METRICS[metric_name], metric_value, tags=tags)

def _get_tablespace_metrics(self, con):
query = "SELECT TABLESPACE_NAME, BYTES, MAXBYTES FROM sys.dba_data_files"
cur = con.cursor()
cur.execute(query)
for row in cur:
tablespace_tag = 'tablespace:%s' % row[0]
used = row[1]
size = row[2]
in_use = used / size * 100
self.gauge('oracle.tablespace.used', used, tags=[tablespace_tag])
self.gauge('oracle.tablespace.size', size, tags=[tablespace_tag])
self.gauge('oracle.tablespace.in_use', in_use, tags=[tablespace_tag])
64 changes: 64 additions & 0 deletions oracle/ci/oracle.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
require 'ci/common'

def oracle_version
ENV['FLAVOR_VERSION'] || 'latest'
end

def oracle_rootdir
"#{ENV['INTEGRATIONS_DIR']}/oracle_#{oracle_version}"
end

namespace :ci do
namespace :oracle do |flavor|
task before_install: ['ci:common:before_install']

task install: ['ci:common:install'] do
use_venv = in_venv
install_requirements('oracle/requirements.txt',
"--cache-dir #{ENV['PIP_CACHE']}",
"#{ENV['VOLATILE_DIR']}/ci.log", use_venv)
# sample docker usage
# sh %(docker create -p XXX:YYY --name oracle source/oracle:oracle_version)
# sh %(docker start oracle)
end

task before_script: ['ci:common:before_script']

task script: ['ci:common:script'] do
this_provides = [
'oracle'
]
Rake::Task['ci:common:run_tests'].invoke(this_provides)
end

task before_cache: ['ci:common:before_cache']

task cleanup: ['ci:common:cleanup']
# sample cleanup task
# task cleanup: ['ci:common:cleanup'] do
# sh %(docker stop oracle)
# sh %(docker rm oracle)
# end

task :execute do
exception = nil
begin
%w(before_install install before_script).each do |u|
Rake::Task["#{flavor.scope.path}:#{u}"].invoke
end
Rake::Task["#{flavor.scope.path}:script"].invoke
Rake::Task["#{flavor.scope.path}:before_cache"].invoke
rescue => e
exception = e
puts "Failed task: #{e.class} #{e.message}".red
end
if ENV['SKIP_CLEANUP']
puts 'Skipping cleanup, disposable environments are great'.yellow
else
puts 'Cleaning up'
Rake::Task["#{flavor.scope.path}:cleanup"].invoke
end
raise exception if exception
end
end
end
30 changes: 30 additions & 0 deletions oracle/conf.yaml.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
init_config:

instances:
# The Oracle check requires access to the `cx_Oracle` Python
# module. Due to restrictions on installation, this requires
# the following steps in order to be included with the agent
#
# 1. Download the relevant Oracle Instant Client:
# http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html
# Both the basic client and the client sdk will be required
# Example dir: ~/oracle
# 2. Decompress this library in a given directory available to
# all users on the given machine (i.e. /opt/oracle)
# mkdir -p /opt/oracle/ && cd /opt/oracle/
# unzip ~/oracle/instantclient-basic-linux.x64-12.1.0.2.0.zip
# unzip ~/oracle/instantclient-sdk-linux.x64-12.1.0.2.0.zip
# 3. Set required env variables for cx_Oracle installation
# export LD_RUN_PATH=/opt/oracle/instantclient_12_1
# export ORACLE_HOME=/opt/oracle/instantclient_12_1
# 4. Install instant client in agent's virtual environment
# /opt/datadog-agent/embedded/bin/pip install cx_Oracle
# 5. Following cx_Oracle installation, ensure LD_LIBRARY_PATH points
# to this directory when starting/restarting the agent
# export LD_LIBRARY_PATH=/opt/oracle/instantclient_12_1
#
- server: 127.0.0.1
user: my_username
password: my_password
tags:
- my_tag
11 changes: 11 additions & 0 deletions oracle/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"maintainer": "help@datadoghq.com",
"manifest_version": "0.1.0",
"max_agent_version": "6.0.0",
"min_agent_version": "5.6.3",
"name": "oracle",
"short_description": "oracle description.",
"support": "contrib",
"supported_os": ["linux","mac_os","windows"],
"version": "0.1.0"
}
1 change: 1 addition & 0 deletions oracle/metadata.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
metric_name,metric_type,interval,unit_name,per_unit_name,description,orientation,integration,short_name
1 change: 1 addition & 0 deletions oracle/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# integration pip requirements
69 changes: 69 additions & 0 deletions oracle/test_oracle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# (C) Datadog, Inc. 2010-2016
# All rights reserved
# Licensed under Simplified BSD License (see LICENSE)

# stdlib
import logging
from types import ListType
import unittest

# 3p
from nose.plugins.attrib import attr

# project
from tests.checks.common import get_check


logging.basicConfig()

"""
Uses Oracle instance running in VM from:
https://atlas.hashicorp.com/woznial/boxes/centos-6.3-oracle-xe

Include following line in your Vagrantfile:

config.vm.network "forwarded_port", guest: 1521, host: 8521

Using the "system" user as permission granting not available
for default "system" user

Install oracle instant client in /opt/oracle

Set up Oracle instant client:
http://jasonstitt.com/cx_oracle_on_os_x

Set:
export ORACLE_HOME=/opt/oracle/instantclient_12_1/
export DYLD_LIBRARY_PATH="$ORACLE_HOME:$DYLD_LIBRARY_PATH"
"""

CONFIG = """
init_config:

instances:
- server: 127.0.0.1:8521
user: system
password: manager
"""

@attr(requires='oracle')
class TestOracle(unittest.TestCase):
"""Basic Test for oracle integration."""
CHECK_NAME = 'oracle'

def testOracle(self):
check, instances = get_check('oracle', CONFIG)
check.check(instances[0])
metrics = check.get_metrics()

# Make sure the base metrics loaded
base_metrics = check.SYS_METRICS.values()
ret_metrics = [m[0] for m in metrics]
for metric in base_metrics:
assert metric in ret_metrics

service_checks = check.get_service_checks()
service_checks_count = len(service_checks)
self.assertTrue(isinstance(metrics, ListType))
self.assertTrue(service_checks_count > 0)
self.assertEquals(len([sc for sc in service_checks if sc['check'] == check.SERVICE_CHECK_NAME]), 1, service_checks)