แสดงบทความที่มีป้ายกำกับ PHP แสดงบทความทั้งหมด
แสดงบทความที่มีป้ายกำกับ PHP แสดงบทความทั้งหมด

วันจันทร์ที่ 13 มกราคม พ.ศ. 2557

Cacti + ORACLE ตอนที่ 4: Multiple output และ Data input field in graph title

ความเดิมตอนที่แล้วเราสามารถสร้างกราฟได้แล้ว ในบทนี้จะเพิ่มเิติมถึงการกำหนด title ของกราฟให้อ่านง่ายและสามารถรู้ว่ากราฟนี้เป็นหัวข้อใด มาจาก server ใหนและ Instance ชื่ออะไร รวมถึงตัวอย่างการรับค่าจาก Data Input Method แบบหลาย output ในครั้งเดียว และนำมาสร้างกราฟที่แสดงข้อมูลหลายชนิดพร้อมๆักัน

Data input field in graph title
เริ่มจาก download และติดตั้งตามตัวอย่างจาก Link นี้
http://forums.cacti.net/viewtopic.php?f=5&t=42802

1. Place 'addon_data_input_field.php' at 'cacti/lib/' directory
2. Modify get_graph_title() in 'cacti/lib/functions.php' as follows:
function get_graph_title($local_graph_id) {
        global $config;
        include_once($config["library_path"] . "/addon_data_input_field.php");

        $graph = db_fetch_row("select
                graph_local.host_id,
                graph_local.snmp_query_id,
                graph_local.snmp_index,
                graph_templates_graph.title
                from (graph_templates_graph,graph_local)
                where graph_templates_graph.local_graph_id=graph_local.id
                and graph_local.id=$local_graph_id");

        if ((strstr($graph["title"], "|")) && (!empty($graph["host_id"]))) {
                $graph["title"] = substitute_data_input_field($graph["title"], $graph["host_id"], $local_graph_id);
                return expand_title($graph["host_id"], $graph["snmp_query_id"], $graph["snmp_index"], $graph["title"]);
        }else{
                return $graph["title"];
        }
}

Multiple Output
ตัวอย่างนี้จะเป็นการสร้างกราฟ Tablespace usage monitor

1.ให้สร้าง Data Input Method ใหม่ชื่อว่า Oracle Tablespaces Monitor ดังรูป

2.สร้างสคริปท์ ss_oracle_tbls.php ที่ path <path_cacti>/scripts
<?
/* do NOT run this script through a web browser */
if (!isset($_SERVER["argv"][0]) || isset($_SERVER['REQUEST_METHOD'])  || isset($_SERVER['REMOTE_ADDR'])) {
   die("<br><strong>This script is only meant to run at the command line.</strong>");
}

/* display No errors */
error_reporting(0);

if (!isset($called_by_script_server)) {
        array_shift($_SERVER["argv"]);

        print call_user_func_array("ss_oracle_tbls", $_SERVER["argv"])."\n";
}

function ss_oracle_tbls ($tnsnames, $sql_path, $username, $password,$tablespacename) {

        putenv("ORACLE_HOME=/u01/app/oracle/product/11.2.0/db_1");
        putenv("TNS_ADMIN=/u01/app/oracle/product/11.2.0/db_1/network/admin");

        $ret = '';

        $gdb_conn = ocilogon($username, $password,$tnsnames);

        $gdb_statement = OCIParse ($gdb_conn, "alter session set nls_date_format='MM/DD/YYYY HH24:MI:SS' ");
        OCIExecute ($gdb_statement);

        if (! OCIExecute($gdb_statement)){
                        return;
        }

        include $sql_path;

        $gdb_statement = OCIParse ($gdb_conn, $query);
        OCIExecute ($gdb_statement);

        while (OCIFetchInto ($gdb_statement, $row, OCI_RETURN_NULLS + OCI_ASSOC)) {
                reset($row);

                $tbls_current=$row['CURR'];
                                $tbls_free=$row['FREE'];
                                $tbls_total=$row['TOTAL'];
                                $tbls_curr_percent=$row['CURRENT_PERCENT'];

        }

        OCIFreeStatement($gdb_statement);

        $ret .= 'current:'.$tbls_current.' current_percent:'.$tbls_curr_percent.' free:'.$tbls_free.' total:'.$tbls_total.' ';

        return trim($ret);
}
?>

3.สร้างสคริปท์ tablespace_usage.php ที่ path <path_cacti>/sql
<?

$query = " SELECT DISTINCT
         a.tablespace_name,
         (SUM (a.bytes) / 1024 / 1024 - ROUND (c.free / 1024 / 1024)) curr,
         (  SUM (DECODE (b.maxextend,
                         NULL, a.bytes / 1024 / 1024,
                           b.maxextend
                         * (SELECT VALUE
                              FROM v\$parameter
                             WHERE name = 'db_block_size')
                         / 1024
                         / 1024))
          - (SUM (a.bytes) / 1024 / 1024 - ROUND (c.Free / 1024 / 1024)))
            free,
         SUM (DECODE (b.maxextend,
                      NULL, a.bytes / 1024 / 1024,
                        b.maxextend
                      * (SELECT VALUE
                           FROM v\$parameter
                          WHERE name = 'db_block_size')
                      / 1024
                      / 1024))
            total,
         ROUND (  100
                * (SUM (a.bytes) / 1024 / 1024 - ROUND (c.free / 1024 / 1024))
                / (SUM (DECODE (b.maxextend,
                                NULL, a.bytes / 1024 / 1024,
                                  b.maxextend
                                * (SELECT VALUE
                                     FROM v\$parameter
                                    WHERE name = 'db_block_size')
                                / 1024
                                / 1024))))
            current_percent
    FROM dba_data_files a,
         sys.filext$ b,
         (  SELECT d.tablespace_name, SUM (NVL (c.bytes, 0)) free
              FROM dba_tablespaces d, dba_free_space c
             WHERE d.tablespace_name = c.tablespace_name(+)
          GROUP BY d.tablespace_name) c
   WHERE     a.file_id = b.file#(+)
         AND a.tablespace_name = c.tablespace_name
         AND a.tablespace_name = UPPER ('$tablespacename')
GROUP BY a.tablespace_name, c.free / 1024 ";

?>

4.สร้าง Data templates และ Graph templates ดังนี้
กดไปตาม Link จนถึงหน้า download จากนั้นนำไป import ยังระบบ Cacti ของท่าน
tablespace_data_template.xml
tablespace_graph_template.xml

เมื่อเปิดดู Data Templates จะเห็นว่ามีการสร้าง Internal Data Source Name มาเท่ากับ output จากสคริปท์ PHP

5. เปิดดุ Graph Templates จะเห็นว่าที่ช่อง title จะมีการใส่ parameter เข้าไปเพื่อให้แสดงว่ากราฟนี้มีข้อมูลมาจาก input อย่างไรบ้าง
|host_description|/|input_tnsnames| - Tablespace - |input_tablespace_name|

6. เปิดเมนู Management -> Data Sources แล้ว Click ที่ Add

ใส่ข้อมูล Data Source Fields -> Name ดังนี้
|host_description| - Tablespace - |input_tnsnames| : |input_tablespace_name|

7.กำหนด SQL script path ให้ตรงกับไฟล์ Tablespace_usage.php

8.เปิดเมนุ Management -> Graph Management แล้ว Click ที่ Add

เมื่อกำหนดค่าตามที่ต้องการแล้วให้กดที่ Save

หลักจากนั้นเมื่อเปิดดูรูปจะสังเกตูเห็นว่ามีข้อมูลแสดงที่ Title ออกมาอย่างครบถ้วนและข้อมูลของกราฟสามารถแสดงรายละเีอียดจากหลาย output ได้แล้ว


หมายเหตุ
จากตัวอย่างจะเป็นการ Monitor Tablespace usage ที่ไม่ได้ใช้ระบบ Auto-Extend เราจึงสังเกตุแค่ค่า Max หรือ Total space ว่ามีค่า used และ free เท่าใหร่ โดยไม่ได้สนใจว่าพร้อมสำหรับขยายอย่างไร การทำแบบนี้เป็นที่นิยมในระบบส่วนใหญ่เพราะจะได้ไม่ต้องกังวลกับ OS Disk หรือ Storage จะเต็มโดยที่เราไม่รู้ตัวหรือเปล่าเพราะกำหนดตายตัวไปแล้วว่าให้ Database ใช้ไปเท่าใหร่ แล้วค่อยมาดูว่าแต่ะละ Tablespace จะเต็ํมหรือยังจะได้ทำการ Add new datafiles

วันอังคารที่ 7 มกราคม พ.ศ. 2557

Cacti + ORACLE ตอนที่ 1: สร้างสคริปท์ PHP เพื่ออ่านค่าจากฐานข้อมูล

ในกาีรทำงานของ Cacti ที่จะสร้าง poller ไปทำการ query ข้อมูลจากระบบที่ต้องการนั้นจะใช้การทำงานจาก SNMP โปรโตคอลเป็นหลัก แต่ในบางกรณีที่เป็นการ query ข้อมูลที่มีลักษณะพิเศษหรือเป็นการทำงานเฉพาะกิจบางอย่างนั้น จะไม่ได้มี SNMP มาให้ เราจึงต้องใช้วิธีการอื่นเพื่อใช้ query ข้อมูลออกมา

สำหรับ ORACLE Database ที่เราจะทำกันในบทนี้เราจะใช้วิธีที่เรียกว่า Data Input Methods ที่มีให้เลือกใช้ในเมนูของ Cacti ดังรูป


ในตัวอย่างนี้ผมจะสร้าง Data Input Methods ใหม่ขึ้นมาตั้งชื่อว่า Oracle Monitor Query เป็นฟังชั่นที่เราจะนำมาใช้สำหรับการ connect ไปยังระบบฐานข้อมูล ORACLE โดยฟังชั่นที่เราสร้างขึ้นมานี้ จะสามารถรับ input เพื่อนำไปประมวลผลค่าออกมาได้ ดังนั้นเราจะสร้างแค่ครั้งเีดียวแล้วจะประยุกต์ใช้ในการทำงานกับแต่ะละ SQL ที่เราจะนำไป query ได้จากหลายๆระบบ

Input Type กำหนดเป็น Script - Script Server (PHP) เพราะเราจะใช้การเรียก php สคริปท์จาก command line เพื่อติดต่อไปยังฐานข้อมูล ORACLE โดยใน php.ini เราจะต้องทำการติดตั้ง module เพื่อการใช้งาน จากตัวอย่างสคริปท์ของผมใช้ oci8 จากการติดตั้ง ORACLE client

Input String
path_cacti  path ที่อยู่ของ cacti (ของผมคือ /usr/share/cacti มาจากการติดตั้งด้วย YUM หากท่านใช้วิธีอื่นจะไม่เหมือนกัน)

/scripts/ss_oracle_query.php ss_oracle_query คือ sub folder ใน cacti ที่ระบุถึง php สคริปท์ที่เราต้องการให้รันเพื่อ query ค่าจาก ORACLE (ss_oracle_query ตัวที่สองใช้เพื่อระบุ function ในสคริปท์ที่เราต้องการ call)

tnsnamesค่า tnsnames หรือชื่อที่เรากำหนดไว้ในไฟล์ tnsnames.ora ที่เราได้ทำการกำหนด connection description เอาไว้

path_oracle_sql เพื่อที่เราจะสามารถกำหนด SQL Statement ได้โดยอิสระสำหรับแต่ละ query ที่เราจะใช้งาน ผมจึงกำหนดให้เป็น path ที่ระบุไปยัง php ไฟล์ที่เราจะนำมา include ไปในสคริปท์ ss_oracle_query.php ที่เป็นตัวรันอีกครั้งหนึ่ง สาเหตุที่ไม่ได้ทำเป็นไฟล์ .sql หรือรับค่าเป็น statement ไปเลยก็เพราะว่าการรันใน php จะต้องทำการแก้ escape character บางอย่างเสียก่อน ไม่สามารถรันได้ทันที (สคริปท์ SQL ที่ต้องทำเป็น PHP นั้นผมจะสอนวิธีการทำ และจะนำมาแจกในบทความต่อๆไปครับ)

user username สำหรับ login เพื่อเข้าไป query ยัง Database ที่เราต้องการ

password password สำหรับ login เพื่อเข้าไป query ยัง Database ที่เราต้องการ


ตัวอย่าง php สคริปท์ที่ใช้ใน parameter path_oracle_sql
/usr/share/cacti/sql/shared_pool_free.php
<?

$query = "      select
                        round(
                                (sum(decode(name,'free memory',bytes))/sum(bytes))*100
                        ,2) as free
                from v\$sgastat
                where pool = 'shared pool'  ";

?>


Source code ของสคริปท์หลักที่ใช้เพื่อ query ข้อมูล
/usr/share/cacti/scripts/ss_oracle_query.php
<?
/* do NOT run this script through a web browser */
if (!isset($_SERVER["argv"][0]) || isset($_SERVER['REQUEST_METHOD'])  || isset($_SERVER['REMOTE_ADDR'])) {
   die("<br><strong>This script is only meant to run at the command line.</strong>");
}

/* display No errors */
error_reporting(0);

if (!isset($called_by_script_server)) {
        array_shift($_SERVER["argv"]);

        print call_user_func_array("ss_oracle_query", $_SERVER["argv"])."\n";
}

function ss_oracle_query ($tnsnames, $sql_path, $username, $password) {

        putenv("ORACLE_HOME=/u01/app/oracle/product/11.2.0/db_1");
        putenv("TNS_ADMIN=/u01/app/oracle/product/11.2.0/db_1/network/admin");

        $ret = '';

        $gdb_conn = ocilogon($username, $password,$tnsnames);

        $gdb_statement = OCIParse ($gdb_conn, "alter session set nls_date_format='MM/DD/YYYY HH24:MI:SS' ");
        OCIExecute ($gdb_statement);

        if (! OCIExecute($gdb_statement)){
                        return;
        }

        include $sql_path;

        $gdb_statement = OCIParse ($gdb_conn, $query);
        OCIExecute ($gdb_statement);

        while (OCIFetchInto ($gdb_statement, $row, OCI_RETURN_NULLS + OCI_ASSOC)) {
                reset($row);

                $shared_pool_free=$row['FREE'];
        }

        OCIFreeStatement($gdb_statement);

        $ret .= 'value:'.$shared_pool_free.' ';

        return trim($ret);
}
?>

ข้อควรระวัง
putenv("ORACLE_HOME=/u01/app/oracle/product/11.2.0/db_1");
putenv("TNS_ADMIN=/u01/app/oracle/product/11.2.0/db_1/network/admin");
2 บรรทัดนี้ในไฟล์ ss_oracle_query.php ท่านจะต้องแก้ให้ตรงกับระบบที่ท่านใช้งานในการกำหนด Environment เพื่อให้ PHP OCI8 ใช้งานในการเชื่อมต่อไปยังฐานข้อมูล ORACLE