From f928f9a6cdd782fa6bbe813747774d49400e27dd Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Tue, 17 Oct 2006 02:01:20 +0000 Subject: [PATCH] API * Better log events info * Added RAW debugging format --- includes/api/ApiBase.php | 75 ++++++++++++++--------- includes/api/ApiFormatJson.php | 9 ++- includes/api/ApiFormatXml.php | 4 +- includes/api/ApiMain.php | 5 ++ includes/api/ApiQueryAllpages.php | 4 +- includes/api/ApiQueryLogEvents.php | 98 ++++++++++++++++++++++++------ includes/api/ApiQueryRevisions.php | 7 +-- includes/api/ApiQueryWatchlist.php | 4 +- 8 files changed, 144 insertions(+), 62 deletions(-) diff --git a/includes/api/ApiBase.php b/includes/api/ApiBase.php index 8e1974bb81..e0ed028eec 100644 --- a/includes/api/ApiBase.php +++ b/includes/api/ApiBase.php @@ -35,6 +35,11 @@ abstract class ApiBase { const PARAM_MAX2 = 4; const PARAM_MIN = 5; + const LIMIT_BIG1 = 500; // Fast query, user's limit + const LIMIT_BIG2 = 5000; // Fast query, bot's limit + const LIMIT_SML1 = 50; // Slow query, user's limit + const LIMIT_SML2 = 500; // Slow query, bot's limit + private $mMainModule, $mModuleName, $mParamPrefix; /** @@ -42,7 +47,7 @@ abstract class ApiBase { */ public function __construct($mainModule, $moduleName, $paramPrefix = '') { $this->mMainModule = $mainModule; - $this->mModuleName = $moduleName; + $this->mModuleName = $moduleName; $this->mParamPrefix = $paramPrefix; } @@ -51,22 +56,22 @@ abstract class ApiBase { */ public abstract function execute(); - /** - * Get the name of the module being executed by this instance - */ - public function getModuleName() { - return $this->mModuleName; - } - - /** - * Get the name of the module as shown in the profiler log - */ - public function getModuleProfileName($db = false) { - if ($db) - return 'API:' . $this->mModuleName . '-DB'; - else - return 'API:' . $this->mModuleName; - } + /** + * Get the name of the module being executed by this instance + */ + public function getModuleName() { + return $this->mModuleName; + } + + /** + * Get the name of the module as shown in the profiler log + */ + public function getModuleProfileName($db = false) { + if ($db) + return 'API:' . $this->mModuleName . '-DB'; + else + return 'API:' . $this->mModuleName; + } /** * Get main module @@ -161,23 +166,21 @@ abstract class ApiBase { $paramsDescription = $this->getParamDescription(); $msg = ''; $paramPrefix = "\n" . str_repeat(' ', 19); - foreach ($params as $paramName => &$paramSettings) { + foreach ($params as $paramName => & $paramSettings) { $desc = isset ($paramsDescription[$paramName]) ? $paramsDescription[$paramName] : ''; if (is_array($desc)) $desc = implode($paramPrefix, $desc); if (isset ($paramSettings[self :: PARAM_TYPE])) { $type = $paramSettings[self :: PARAM_TYPE]; if (is_array($type)) { - $desc .= $paramPrefix . 'Allowed values: '. implode(', ', $type); + $desc .= $paramPrefix . 'Allowed values: ' . implode(', ', $type); } } - - $default = is_array($paramSettings) - ? (isset ($paramSettings[self :: PARAM_DFLT]) ? $paramSettings[self :: PARAM_DFLT] : null) - : $paramSettings; + + $default = is_array($paramSettings) ? (isset ($paramSettings[self :: PARAM_DFLT]) ? $paramSettings[self :: PARAM_DFLT] : null) : $paramSettings; if (!is_null($default) && $default !== false) $desc .= $paramPrefix . "Default: $default"; - + $msg .= sprintf(" %-14s - %s\n", $this->encodeParamName($paramName), $desc); } return $msg; @@ -213,7 +216,7 @@ abstract class ApiBase { protected function getParamDescription() { return false; } - + /** * This method mangles parameter name based on the prefix supplied to the constructor. * Override this method to change parameter name during runtime @@ -250,7 +253,7 @@ abstract class ApiBase { * Using the settings determine the value for the given parameter * @param $paramName String: parameter name * @param $paramSettings Mixed: default value or an array of settings using PARAM_* constants. - */ + */ protected function getParameterFromSettings($paramName, $paramSettings) { // Some classes may decide to change parameter names @@ -284,7 +287,7 @@ abstract class ApiBase { } else { $value = $this->getMain()->getRequest()->getVal($paramName, $default); } - + if (isset ($value) && ($multi || is_array($type))) $value = $this->parseMultiValue($paramName, $value, $multi, is_array($type) ? $type : null); @@ -328,7 +331,7 @@ abstract class ApiBase { // There should never be any duplicate values in a list if (is_array($value)) $value = array_unique($value); - + return $value; } @@ -418,9 +421,21 @@ abstract class ApiBase { $this->mModuleTime += microtime(true) - $this->mTimeIn; $this->mTimeIn = 0; - wfProfileOut($this->getModuleProfileName()); + wfProfileOut($this->getModuleProfileName()); } + /** + * When modules crash, sometimes it is needed to do a profileOut() regardless + * of the profiling state the module was in. This method does such cleanup. + */ + public function safeProfileOut() { + if ($this->mTimeIn !== 0) { + if ($this->mDBTimeIn !== 0) + $this->profileDBOut(); + $this->profileOut(); + } + } + /** * Total time the module was executed */ @@ -474,7 +489,7 @@ abstract class ApiBase { } public abstract function getVersion(); - + public static function getBaseVersion() { return __CLASS__ . ': $Id$'; } diff --git a/includes/api/ApiFormatJson.php b/includes/api/ApiFormatJson.php index 48de5af59a..7e72693086 100644 --- a/includes/api/ApiFormatJson.php +++ b/includes/api/ApiFormatJson.php @@ -31,14 +31,21 @@ if (!defined('MEDIAWIKI')) { class ApiFormatJson extends ApiFormatBase { + private $mIsRaw; + public function __construct($main, $format) { parent :: __construct($main, $format); + $this->mIsRaw = ($format === 'raw' || $format === 'rawfm'); } public function getMimeType() { return 'application/json'; } - + + public function getNeedsRawData() { + return $this->mIsRaw; + } + public function execute() { if (!function_exists('json_encode') || $this->getIsHtml()) { $json = new Services_JSON(); diff --git a/includes/api/ApiFormatXml.php b/includes/api/ApiFormatXml.php index f4bf838785..09621f6702 100644 --- a/includes/api/ApiFormatXml.php +++ b/includes/api/ApiFormatXml.php @@ -104,8 +104,6 @@ class ApiFormatXml extends ApiFormatBase { $subElements = array (); foreach ($elemValue as $subElemId => & $subElemValue) { if (gettype($subElemId) === 'integer') { - if (!is_array($subElemValue)) - ApiBase :: dieDebug(__METHOD__, "($elemName, ...) has a scalar indexed value."); $indElements[] = $subElemValue; unset ($elemValue[$subElemId]); } elseif (is_array($subElemValue)) { @@ -115,7 +113,7 @@ class ApiFormatXml extends ApiFormatBase { } if (is_null($subElemIndName) && !empty ($indElements)) - ApiBase :: dieDebug(__METHOD__, "($elemName, ...) has integer keys without _element value"); + ApiBase :: dieDebug(__METHOD__, "($elemName, ...) has integer keys without _element value. Use ApiResult::setIndexedTagName()."); if (!empty ($subElements) && !empty ($indElements) && !is_null($subElemContent)) ApiBase :: dieDebug(__METHOD__, "($elemName, ...) has content and subelements"); diff --git a/includes/api/ApiMain.php b/includes/api/ApiMain.php index 53f0cf1d0b..9803e033ac 100644 --- a/includes/api/ApiMain.php +++ b/includes/api/ApiMain.php @@ -57,6 +57,8 @@ class ApiMain extends ApiBase { private static $Formats = array ( 'json' => 'ApiFormatJson', 'jsonfm' => 'ApiFormatJson', + 'raw' => 'ApiFormatJson', + 'rawfm' => 'ApiFormatJson', 'xml' => 'ApiFormatXml', 'xmlfm' => 'ApiFormatXml', 'yaml' => 'ApiFormatYaml', @@ -169,6 +171,9 @@ class ApiMain extends ApiBase { ob_clean(); $this->mResult->Reset(); $this->mResult->addValue(null, 'error', $errMessage); + + // If the error occured during printing, do a printer->profileOut() + $this->mPrinter->safeProfileOut(); $this->printResult(true); } diff --git a/includes/api/ApiQueryAllpages.php b/includes/api/ApiQueryAllpages.php index 0966445ece..5e01222b84 100644 --- a/includes/api/ApiQueryAllpages.php +++ b/includes/api/ApiQueryAllpages.php @@ -142,8 +142,8 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase { ApiBase :: PARAM_DFLT => 10, ApiBase :: PARAM_TYPE => 'limit', ApiBase :: PARAM_MIN => 1, - ApiBase :: PARAM_MAX1 => 500, - ApiBase :: PARAM_MAX2 => 5000 + ApiBase :: PARAM_MAX1 => ApiBase :: LIMIT_BIG1, + ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 )); } diff --git a/includes/api/ApiQueryLogEvents.php b/includes/api/ApiQueryLogEvents.php index 77d87db229..7da11b02d8 100644 --- a/includes/api/ApiQueryLogEvents.php +++ b/includes/api/ApiQueryLogEvents.php @@ -36,14 +36,14 @@ class ApiQueryLogEvents extends ApiQueryBase { } public function execute() { - $limit = $type = $from = $to = $dir = $user = $title = $namespace = null; + $limit = $type = $start = $end = $dir = $user = $title = null; extract($this->extractRequestParams()); $db = $this->getDB(); extract($db->tableNames('logging', 'page', 'user'), EXTR_PREFIX_ALL, 'tbl'); - - $tables = "$tbl_logging LEFT OUTER JOIN $tbl_page ON log_namespace=page_namespace AND log_title=page_title " . + $tables = "$tbl_logging LEFT OUTER JOIN $tbl_page ON " . + "log_namespace=page_namespace AND log_title=page_title " . "INNER JOIN $tbl_user ON user_id=log_user"; $fields = array ( @@ -80,11 +80,19 @@ class ApiQueryLogEvents extends ApiQueryBase { $where['log_title'] = $titleObj->getDBkey(); } - // $where[] = "log_timestamp $direction '$safetime'"; + $dirNewer = ($dir === 'newer'); + $before = ($dirNewer ? '<=' : '>='); + $after = ($dirNewer ? '>=' : '<='); + + if (!is_null($start)) + $where[] = 'log_timestamp' . $after . $db->addQuotes($start); + if (!is_null($end)) + $where[] = 'log_timestamp' . $before . $db->addQuotes($end); $options = array ( - 'LIMIT' => $limit +1 - ); + 'LIMIT' => $limit +1, + 'ORDER BY' => 'log_timestamp' . ($dirNewer ? '' : ' DESC' + )); $this->profileDBIn(); $res = $db->select($tables, $fields, $where, __METHOD__, $options); @@ -95,27 +103,42 @@ class ApiQueryLogEvents extends ApiQueryBase { while ($row = $db->fetchObject($res)) { if (++ $count > $limit) { // We've reached the one extra which shows that there are additional pages to be had. Stop here... - $this->setContinueEnumParameter('from', ApiQueryBase :: keyToTitle($row->page_title)); + $this->setContinueEnumParameter('start', ApiQueryBase :: keyToTitle($row->log_timestamp)); break; } $vals = array ( - 'type' => $row->log_type, - 'action' => $row->log_action, + 'action' => "$row->log_type/$row->log_action", 'timestamp' => $row->log_timestamp, 'comment' => $row->log_comment, - 'params' => $row->log_params, - 'pageid' => intval($row->page_id) - ); - + 'pageid' => intval($row->page_id + )); + $title = Title :: makeTitle($row->log_namespace, $row->log_title); $vals['ns'] = $title->getNamespace(); $vals['title'] = $title->getPrefixedText(); + if ($row->log_params !== '') { + $params = explode("\n", $row->log_params); + if ($row->log_type == 'move' && isset ($params[0])) { + $destTitle = Title :: newFromText($params[0]); + if ($destTitle) { + $vals['tons'] = $destTitle->getNamespace(); + $vals['totitle'] = $destTitle->getPrefixedText(); + $params = null; + } + } + + if(!empty($params)) { + ApiResult :: setIndexedTagName($params, 'param'); + $vals = array_merge($vals, $params); + } + } + if (!$row->log_user) $vals['anon'] = ''; $vals['user'] = $row->user_name; - + $data[] = $vals; } $db->freeResult($res); @@ -125,21 +148,56 @@ class ApiQueryLogEvents extends ApiQueryBase { } protected function getAllowedParams() { - return array ( 'limit' => array ( ApiBase :: PARAM_DFLT => 10, ApiBase :: PARAM_TYPE => 'limit', ApiBase :: PARAM_MIN => 1, - ApiBase :: PARAM_MAX1 => 500, - ApiBase :: PARAM_MAX2 => 5000 - ) + ApiBase :: PARAM_MAX1 => ApiBase :: LIMIT_BIG1, + ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 + ), + 'type' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => array ( + 'block', + 'protect', + 'rights', + 'delete', + 'upload', + 'move', + 'import', + 'renameuser', + 'newusers', + 'makebot' + ) + ), + 'start' => array ( + ApiBase :: PARAM_TYPE => 'timestamp' + ), + 'end' => array ( + ApiBase :: PARAM_TYPE => 'timestamp' + ), + 'dir' => array ( + ApiBase :: PARAM_DFLT => 'older', + ApiBase :: PARAM_TYPE => array ( + 'newer', + 'older' + ) + ), + 'user' => null, + 'title' => null ); } protected function getParamDescription() { return array ( - 'limit' => 'How many total items to return.' + 'limit' => '', + 'type' => '', + 'start' => '', + 'end' => '', + 'dir' => '', + 'user' => '', + 'title' => '' ); } @@ -154,7 +212,7 @@ class ApiQueryLogEvents extends ApiQueryBase { } public function getVersion() { - return __CLASS__ . ': $Id:$'; + return __CLASS__ . ': $Id$'; } } ?> \ No newline at end of file diff --git a/includes/api/ApiQueryRevisions.php b/includes/api/ApiQueryRevisions.php index 1fbc357701..729b6237b6 100644 --- a/includes/api/ApiQueryRevisions.php +++ b/includes/api/ApiQueryRevisions.php @@ -245,11 +245,10 @@ class ApiQueryRevisions extends ApiQueryBase { ) ), 'limit' => array ( - ApiBase :: PARAM_DFLT => null, ApiBase :: PARAM_TYPE => 'limit', - ApiBase :: PARAM_MIN => 0, - ApiBase :: PARAM_MAX1 => 50, - ApiBase :: PARAM_MAX2 => 500 + ApiBase :: PARAM_MIN => 1, + ApiBase :: PARAM_MAX1 => ApiBase :: LIMIT_SML1, + ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_SML2 ), 'startid' => array ( ApiBase :: PARAM_TYPE => 'integer' diff --git a/includes/api/ApiQueryWatchlist.php b/includes/api/ApiQueryWatchlist.php index 92273a1523..a2552f6777 100644 --- a/includes/api/ApiQueryWatchlist.php +++ b/includes/api/ApiQueryWatchlist.php @@ -232,8 +232,8 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase { ApiBase :: PARAM_DFLT => 10, ApiBase :: PARAM_TYPE => 'limit', ApiBase :: PARAM_MIN => 1, - ApiBase :: PARAM_MAX1 => 500, - ApiBase :: PARAM_MAX2 => 5000 + ApiBase :: PARAM_MAX1 => ApiBase :: LIMIT_BIG1, + ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 ), 'prop' => array ( APIBase :: PARAM_ISMULTI => true, -- 2.20.1