/** * Add debugging information include queries and messages to output queue * * @param Util\Debug $debug */ protected function addDebug(Util\Debug $debug) { echo "level:\t" . $debug->getLevel() . PHP_EOL; echo "database:\t" . Util\Configuration::read('db.driver') . PHP_EOL; echo "time:\t" . $debug->getExecutionTime() . PHP_EOL; if ($uptime = Util\Debug::getUptime()) { echo "uptime:\t" . $uptime * 1000; } if ($load = Util\Debug::getLoadAvg()) { echo "load:\t" . implode(', ', $load) . PHP_EOL; } if ($commit = Util\Debug::getCurrentCommit()) { echo "commit-hash:\t" . $commit . PHP_EOL; } if ($version = phpversion()) { echo "php-version:\t" . $version . PHP_EOL; } foreach ($debug->getMessages() as $message) { echo "message:\t" . $message['message'] . PHP_EOL; // TODO add more information } foreach ($debug->getQueries() as $query) { echo "query:\t" . $query['sql'] . PHP_EOL; if (isset($query['parameters'])) { echo "\tparameters:\t" . implode(', ', $query['parameters']) . PHP_EOL; } } }
/** * Render response and send it to the client */ public function send() { if (Util\Debug::isActivated()) { $this->add(Util\Debug::getInstance()); } $this->response->setContent($this->render()); return $this->response; }
/** * @todo * @param string $capabilities * @param string $sub */ public function get($section = NULL) { $capabilities = array(); if (is_null($section) || $section == 'configuration') { $configuration = array('precision' => View\View::PRECISION, 'database' => Util\Configuration::read('db.driver'), 'debug' => Util\Configuration::read('debug'), 'devmode' => Util\Configuration::read('devmode')); if ($commit = Util\Debug::getCurrentCommit()) { $configuration['commit'] = $commit; } $capabilities['configuration'] = $configuration; } // db statistics - only if specifically requested if ($section == 'database') { $conn = $this->em->getConnection(); // get DBAL connection from EntityManager // estimate InnoDB tables to avoid performance penalty $rows = $conn->fetchAssoc('EXPLAIN SELECT COUNT(id) FROM data USE INDEX (PRIMARY)'); if (isset($rows['rows'])) { $rows = $rows['rows']; } else { // get correct values for MyISAM $rows = $conn->fetchColumn('SELECT COUNT(1) FROM data'); } // database disc space consumption $sql = 'SELECT SUM(data_length + index_length) ' . 'FROM information_schema.tables ' . 'WHERE table_schema = ?'; $size = $conn->fetchColumn($sql, array(Util\Configuration::read('db.dbname'))); $aggregation = Util\Configuration::read('aggregation'); $database = array('data_rows' => $rows, 'data_size' => $size, 'aggregation_enabled' => $aggregation ? 1 : 0); // aggregation table size if ($aggregation) { $agg_rows = $conn->fetchColumn('SELECT COUNT(1) FROM aggregate'); $database['aggregation_rows'] = $agg_rows; $database['aggregation_ratio'] = $agg_rows ? $rows / $agg_rows : 0; } $capabilities['database'] = $database; } if (is_null($section) || $section == 'formats') { $capabilities['formats'] = array_keys(Router::$viewMapping); } if (is_null($section) || $section == 'contexts') { $capabilities['contexts'] = array_keys(Router::$controllerMapping); } if (is_null($section) || $section == 'definitions') { // unresolved artifact from Symfony migration // if (!is_null($section)) { // only caching when we don't request dynamic informations // $this->view->setCaching('expires', time()+2*7*24*60*60); // cache for 2 weeks // } $capabilities['definitions']['entities'] = Definition\EntityDefinition::get(); $capabilities['definitions']['properties'] = Definition\PropertyDefinition::get(); } if (count($capabilities) == 0) { throw new \Exception('Invalid capability identifier: \'' . $section . '\''); } return array('capabilities' => $capabilities); }
/** * @param string $section select specific sub section for output */ public function get($section = NULL) { $capabilities = array(); if (is_null($section) || $section == 'configuration') { $configuration = array('precision' => View\View::PRECISION, 'database' => Util\Configuration::read('db.driver'), 'debug' => Util\Configuration::read('debug'), 'devmode' => Util\Configuration::read('devmode')); if ($commit = Util\Debug::getCurrentCommit()) { $configuration['commit'] = $commit; } $capabilities['configuration'] = $configuration; } // db statistics - only if specifically requested if ($section == 'database') { $conn = $this->em->getConnection(); // get DBAL connection from EntityManager // estimate InnoDB tables to avoid performance penalty $rows = $this->sqlCount($conn, 'data'); $size = $this->dbSize($conn, 'data'); $aggregation = Util\Configuration::read('aggregation'); $database = array('data_rows' => $rows, 'data_size' => $size, 'aggregation_enabled' => $aggregation ? 1 : 0); // aggregation table size if ($aggregation) { $agg_rows = $this->sqlCount($conn, 'aggregate'); $agg_size = $this->dbSize($conn, 'aggregate'); $database['aggregation_rows'] = $agg_rows; $database['aggregation_size'] = $agg_size; $database['aggregation_ratio'] = $agg_rows ? $rows / $agg_rows : 0; } $capabilities['database'] = $database; } if (is_null($section) || $section == 'formats') { $capabilities['formats'] = array_keys(Router::$viewMapping); } if (is_null($section) || $section == 'contexts') { $capabilities['contexts'] = array_keys(Router::$controllerMapping); } if (is_null($section) || $section == 'definitions') { // unresolved artifact from Symfony migration if (!is_null($section)) { // only caching when we don't request dynamic informations $this->view->setCaching('expires', time() + 2 * 7 * 24 * 60 * 60); // cache for 2 weeks } $capabilities['definitions']['entities'] = Definition\EntityDefinition::get(); $capabilities['definitions']['properties'] = Definition\PropertyDefinition::get(); } if (count($capabilities) == 0) { throw new \Exception('Invalid capability identifier: \'' . $section . '\''); } return array('capabilities' => $capabilities); }
/** * Add exception to output queue * * @param \Exception $exception * @param boolean $debug */ protected function addException(\Exception $exception) { $exceptionType = explode('\\', get_class($exception)); $exceptionInfo = array('message' => $exception->getMessage(), 'type' => end($exceptionType), 'code' => $exception->getCode()); if (Util\Debug::isActivated()) { $debugInfo = array('file' => $exception->getFile(), 'line' => $exception->getLine(), 'backtrace' => $exception->getTrace()); $this->json['exception'] = array_merge($exceptionInfo, $debugInfo); } else { $this->json['exception'] = $exceptionInfo; } }
/** * Add exception to output queue * * @param \Exception $exception * @param boolean $debug */ protected function addException(\Exception $exception) { echo get_class($exception) . '# [' . $exception->getCode() . ']' . ':' . $exception->getMessage() . PHP_EOL; if (Util\Debug::isActivated()) { echo "#\tfile:" . CSV::DELIMITER . $exception->getFile() . PHP_EOL; echo "#\tline:" . CSV::DELIMITER . $exception->getLine() . PHP_EOL; } }
/** * Determine context, format and uuid of the raw request * * @param Request $request A Request instance * @param int $type The type of the request (for Symfony compatibility, not implemented) * * @return Response A Response instance */ public function handleRaw(Request $request, $type = HttpKernelInterface::MASTER_REQUEST) { // workaround for https://github.com/symfony/symfony/issues/13617 $pathInfo = $request->server->has('PATH_INFO') ? $request->server->get('PATH_INFO') : ''; if (0 === strlen($pathInfo)) { $pathInfo = $request->getPathInfo(); } $format = pathinfo($pathInfo, PATHINFO_EXTENSION); if (!array_key_exists($format, self::$viewMapping)) { if (empty($pathInfo)) { throw new \Exception('Missing or invalid PATH_INFO'); } elseif (empty($this->format)) { throw new \Exception('Missing format'); } else { throw new \Exception('Unknown format: \'' . $this->format . '\''); } } // initialize debugging if (($debugLevel = $request->query->get('debug')) || ($debugLevel = Util\Configuration::read('debug'))) { if ($debugLevel > 0 && !Util\Debug::isActivated()) { new Util\Debug($debugLevel, $this->em); } } else { // make sure static debug instance is removed Util\Debug::deactivate(); } $class = self::$viewMapping[$format]; $this->view = new $class($request, $format); $path = explode('/', substr($pathInfo, 1, strrpos($pathInfo, '.') - 1)); list($context, $uuid) = array_merge($path, array(null)); // verify route if (!array_key_exists($context, self::$controllerMapping)) { throw new \Exception(empty($context) ? 'Missing context' : 'Unknown context: \'' . $context . '\''); } return $this->handler($request, $context, $uuid); }
* A test for our JSON utility class * * @package tests * @copyright Copyright (c) 2011, The volkszaehler.org project * @license http://www.gnu.org/licenses/gpl.txt GNU Public License * @author Steffen Vogel <*****@*****.**> */ /* * This file is part of volkzaehler.org * * volkzaehler.org is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * volkzaehler.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with volkszaehler.org. If not, see <http://www.gnu.org/licenses/>. */ define('VZ_DIR', realpath(__DIR__ . '/../..')); use Volkszaehler\Util; include VZ_DIR . '/lib/Util/Debug.php'; echo '<pre>'; echo print_r(Util\Debug::getLoadAvg(), TRUE); echo Util\Debug::getUptime() . "\n"; echo Util\Debug::getCurrentCommit(); echo '</pre>';
/** * Add exception to output queue * * @param \Exception $exception * @param boolean $debug */ protected function addException(\Exception $exception) { $exceptionType = explode('\\', get_class($exception)); $xmlException = $this->xmlDoc->createElement('exception'); $xmlException->setAttribute('code', $exception->getCode()); $xmlException->setAttribute('type', end($exceptionType)); $xmlException->appendChild($this->xmlDoc->createElement('message', $exception->getMessage())); if (Util\Debug::isActivated()) { $xmlException->appendChild($this->xmlDoc->createElement('file', $exception->getFile())); $xmlException->appendChild($this->xmlDoc->createElement('line', $exception->getLine())); $xmlException->appendChild($this->convertTrace($exception->getTrace())); } $this->xmlRoot->appendChild($xmlException); }
/** * Render response and send it to the client */ public function send() { if (Util\Debug::isActivated()) { $this->add(Util\Debug::getInstance()); } $this->render(); $this->response->send(); }
/** * Core data aggregation * * @param int $channel_id id of channel to perform aggregation on * @param string $interpreter interpreter class name * @param string $mode aggregation mode (full, delta) * @param string $level aggregation level (day...) * @param int $period delta days to aggregate * @return int number of rows */ protected function aggregateChannel($channel_id, $interpreter, $mode, $level, $period) { $format = self::getAggregationDateFormat($level); $type = self::getAggregationLevelTypeValue($level); $weighed_avg = $interpreter == 'Volkszaehler\\Interpreter\\SensorInterpreter'; $sqlParameters = array($type); $sql = 'REPLACE INTO aggregate (channel_id, type, timestamp, value, count) '; if ($weighed_avg) { // get interpreter's aggregation function $aggregationFunction = $interpreter::groupExprSQL('agg.value'); // SQL query similar to MySQLOptimizer group mode $sql .= 'SELECT channel_id, ? AS type, ' . 'MAX(agg.timestamp) AS timestamp, ' . 'COALESCE( ' . 'SUM(agg.val_by_time) / (MAX(agg.timestamp) - MIN(agg.prev_timestamp)), ' . $aggregationFunction . ') AS value, ' . 'COUNT(agg.value) AS count ' . 'FROM ( ' . 'SELECT channel_id, timestamp, value, ' . 'value * (timestamp - @prev_timestamp) AS val_by_time, ' . 'GREATEST(0, IF(@prev_timestamp = NULL, NULL, @prev_timestamp)) AS prev_timestamp, ' . '@prev_timestamp := timestamp ' . 'FROM data ' . 'CROSS JOIN (SELECT @prev_timestamp := NULL) AS vars ' . 'WHERE '; } else { // get interpreter's aggregation function $aggregationFunction = $interpreter::groupExprSQL('value'); $sql .= 'SELECT channel_id, ? AS type, MAX(timestamp) AS timestamp, ' . $aggregationFunction . ' AS value, COUNT(timestamp) AS count ' . 'FROM data WHERE '; } // selected channel only if ($channel_id) { $sqlParameters[] = $channel_id; $sql .= 'channel_id = ? '; } // since last aggregation only if ($mode == 'delta') { if ($channel_id) { // selected channel $sqlTimestamp = 'SELECT UNIX_TIMESTAMP(DATE_ADD(' . 'FROM_UNIXTIME(MAX(timestamp) / 1000, ' . $format . '), ' . 'INTERVAL 1 ' . $level . ')) * 1000 ' . 'FROM aggregate ' . 'WHERE type = ? AND channel_id = ?'; if ($ts = $this->conn->fetchColumn($sqlTimestamp, array($type, $channel_id), 0)) { $sqlParameters[] = $ts; $sql .= 'AND timestamp >= ? '; } } else { // all channels $sqlParameters[] = $type; $sql .= 'AND timestamp >= IFNULL((' . 'SELECT UNIX_TIMESTAMP(DATE_ADD(' . 'FROM_UNIXTIME(MAX(timestamp) / 1000, ' . $format . '), ' . 'INTERVAL 1 ' . $level . ')) * 1000 ' . 'FROM aggregate ' . 'WHERE type = ? AND aggregate.channel_id = data.channel_id ' . '), 0) '; } } // selected number of periods only if ($period) { $sql .= 'AND timestamp >= (SELECT UNIX_TIMESTAMP(DATE_SUB(DATE_FORMAT(NOW(), ' . $format . '), INTERVAL ? ' . $level . ')) * 1000) '; $sqlParameters[] = $period; } // up to before current period $sql .= 'AND timestamp < UNIX_TIMESTAMP(DATE_FORMAT(NOW(), ' . $format . ')) * 1000 '; if ($weighed_avg) { // close inner table $sql .= 'ORDER BY timestamp ' . ') AS agg '; } $sql .= 'GROUP BY channel_id, ' . Interpreter\Interpreter::buildGroupBySQL($level); if (Util\Debug::isActivated()) { echo Util\Debug::getParametrizedQuery($sql, $sqlParameters) . "\n"; } $rows = $this->conn->executeUpdate($sql, $sqlParameters); return $rows; }
/** * Processes the request * * Example: http://sub.domain.local/middleware.php/channel/550e8400-e29b-11d4-a716-446655440000/data.json?operation=edit&title=New Title */ function handler(Request $request, $context, $uuid) { // initialize debugging if (($debugLevel = $request->parameters->get('debug')) || ($debugLevel = Util\Configuration::read('debug'))) { if ($debugLevel > 0) { $this->debug = new Util\Debug($debugLevel, $this->em); } } else { // make sure static debug instance is removed Util\Debug::deactivate(); } // get controller operation if (null === ($operation = $request->parameters->get('operation'))) { $operation = self::$operationMapping[strtolower($request->getMethod())]; } $class = self::$controllerMapping[$context]; $controller = new $class($request, $this->em); $result = $controller->run($operation, $uuid); $this->view->add($result); return $this->view->send(); }