[icinga-checkins] icinga.org: icingaweb2/feature/memory-json-csv-13623: Monitoring: make use of Buffer while serving JSON

git at icinga.org git at icinga.org
Fri Dec 16 15:30:23 CET 2016


Module: icingaweb2
Branch: feature/memory-json-csv-13623
Commit: db6c035114f8131db39e0fd78d712bc07d83f2bc
URL:    https://git.icinga.org/?p=icingaweb2.git;a=commit;h=db6c035114f8131db39e0fd78d712bc07d83f2bc

Author: Alexander A. Klimov <alexander.klimov at icinga.com>
Date:   Fri Dec 16 15:23:07 2016 +0100

Monitoring: make use of Buffer while serving JSON

refs #13623

---

 library/Icinga/File/Json.php                       |  130 ++++++++++++++++++++
 .../monitoring/library/Monitoring/Controller.php   |    7 +-
 2 files changed, 135 insertions(+), 2 deletions(-)

diff --git a/library/Icinga/File/Json.php b/library/Icinga/File/Json.php
new file mode 100644
index 0000000..d0d9296
--- /dev/null
+++ b/library/Icinga/File/Json.php
@@ -0,0 +1,130 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\File;
+
+use Icinga\Exception\IcingaException;
+use Icinga\Util\Buffer;
+use stdClass;
+use Traversable;
+
+/**
+ * Generates JSON from a query result
+ */
+class Json
+{
+    /**
+     * The query to generate JSON from the result of
+     *
+     * @var Traversable
+     */
+    protected $query;
+
+    /**
+     * Cache for {@link render()}
+     *
+     * @var Buffer|null
+     */
+    protected $renderBuffer;
+
+    /**
+     * Json constructor
+     *
+     * @param   Traversable $query  The query to generate JSON from the result of
+     */
+    protected function __construct(Traversable $query)
+    {
+        $this->query = $query;
+    }
+
+    /**
+     * Factory
+     *
+     * @param   Traversable $query  The query to generate JSON from the result of
+     *
+     * @return  static
+     */
+    public static function create(Traversable $query)
+    {
+        return new static($query);
+    }
+
+    /**
+     * Render JSON and pass it to the user agent (as with {@link fpassthru()})
+     */
+    public function dump()
+    {
+        header('Content-Type: application/json');
+        $this->render()->fpassthru();
+    }
+
+    /**
+     * Return the rendered JSON
+     *
+     * @return string
+     */
+    public function __toString()
+    {
+        return (string) $this->render();
+    }
+
+    /**
+     * Return the rendered JSON
+     *
+     * @return Buffer
+     */
+    protected function render()
+    {
+        if ($this->renderBuffer === null) {
+            $this->renderBuffer = new Buffer();
+            $this->renderBuffer->append('[');
+
+            $first = true;
+            foreach ($this->query as $row) {
+                if ($first) {
+                    $first = false;
+                } else {
+                    $this->renderBuffer->append(',');
+                }
+                $this->renderBuffer->append($this->renderRow($row));
+            }
+
+            $this->renderBuffer->append(']');
+        }
+
+        return $this->renderBuffer;
+    }
+
+    /**
+     * Return a JSON string representing the given columns of a single row
+     *
+     * @param   stdClass    $columns
+     *
+     * @return  string
+     *
+     * @throws  IcingaException     In case of an error
+     */
+    protected function renderRow(stdClass $columns)
+    {
+        $result = json_encode($columns);
+        if ($result === false) {
+            if (function_exists('json_last_error_msg')) {
+                // since PHP 5.5
+                $errorMessage = json_last_error_msg();
+            } else {
+                $lastError = json_last_error();
+                $constants = get_defined_constants(true);
+                $errorMessage = 'Unknown error';
+                foreach ($constants['json'] as $constant => $value) {
+                    if ($value === $lastError && substr($constant, 0, 11) === 'JSON_ERROR_') {
+                        $errorMessage = $constant;
+                        break;
+                    }
+                }
+            }
+
+            throw new IcingaException('Couldn\'t encode %s as JSON: %s', print_r($columns, true), $errorMessage);
+        }
+        return $result;
+    }
+}
diff --git a/modules/monitoring/library/Monitoring/Controller.php b/modules/monitoring/library/Monitoring/Controller.php
index fb5943b..877a86f 100644
--- a/modules/monitoring/library/Monitoring/Controller.php
+++ b/modules/monitoring/library/Monitoring/Controller.php
@@ -8,6 +8,7 @@ use Icinga\Exception\QueryException;
 use Icinga\Data\Filter\Filter;
 use Icinga\Data\Filterable;
 use Icinga\File\Csv;
+use Icinga\File\Json;
 use Icinga\Web\Controller as IcingaWebController;
 use Icinga\Web\Url;
 
@@ -39,8 +40,10 @@ class Controller extends IcingaWebController
         }
         if ($this->_getParam('format') === 'json'
             || $this->_request->getHeader('Accept') === 'application/json') {
-            header('Content-type: application/json');
-            echo json_encode($query->getQuery()->fetchAll());
+            while (ob_get_level()) {
+                ob_end_clean();
+            }
+            Json::create($query)->dump();
             exit;
         }
         if ($this->_getParam('format') === 'csv'



More information about the icinga-checkins mailing list