blob: a261896e8b0e8332dcc1428d7fdb2d69d0f232e1 [file] [log] [blame]
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Author: jmaessen@google.com (Jan Maessen)
#include "net/instaweb/htmlparse/public/logging_html_filter.h"
#include "net/instaweb/htmlparse/public/statistics_log.h"
#include "pagespeed/kernel/html/html_element.h"
// TODO(jmarantz): convert to Statistics interface
namespace {
// Printable names of the statistics.
// Must match up with enum Statistic in logging_html_filter.h;
// is this bad for maintenance?
const char* kStatisticNames[] = {
"explicit_close", "implicit_close", "brief_close", "closed", "unclosed",
"spurious_close", "tags", "cdata", "comments", "directives", "documents",
"IE_directives",
};
}
namespace net_instaweb {
LoggingFilter::LoggingFilter() {
Reset();
}
void LoggingFilter::StartDocument() {
++stats_[NUM_DOCUMENTS];
}
void LoggingFilter::StartElement(HtmlElement* element) {
// Does EndElement get called for singleton elements?
if (element->style() != HtmlElement::INVISIBLE) {
++stats_[NUM_UNCLOSED];
++stats_[NUM_TAGS];
}
}
void LoggingFilter::EndElement(HtmlElement* element) {
// Figure out what's up with the element (implicitly vs explicitly closed)
switch (element->style()) {
case HtmlElement::EXPLICIT_CLOSE: {
--stats_[NUM_UNCLOSED];
++stats_[NUM_CLOSED];
++stats_[NUM_EXPLICIT_CLOSED];
break;
}
case HtmlElement::IMPLICIT_CLOSE: {
--stats_[NUM_UNCLOSED];
++stats_[NUM_CLOSED];
++stats_[NUM_IMPLICIT_CLOSED];
break;
}
case HtmlElement::BRIEF_CLOSE: {
--stats_[NUM_UNCLOSED];
++stats_[NUM_CLOSED];
++stats_[NUM_BRIEF_CLOSED];
break;
}
case HtmlElement::INVISIBLE:
case HtmlElement::UNCLOSED: {
// We assumed unmatchedness at StartElement, so do nothing.
break;
}
case HtmlElement::AUTO_CLOSE: {
// Another form of unmated tag, again do nothing.
break;
}
}
}
void LoggingFilter::Cdata(HtmlCdataNode* cdata) {
++stats_[NUM_CDATA];
}
void LoggingFilter::Comment(HtmlCommentNode* comment) {
++stats_[NUM_COMMENTS];
}
void LoggingFilter::IEDirective(HtmlIEDirectiveNode* directive) {
++stats_[NUM_IE_DIRECTIVES];
}
void LoggingFilter::Directive(HtmlDirectiveNode* directive) {
++stats_[NUM_DIRECTIVES];
}
// Logging, diffing, and aggregation
void LoggingFilter::LogStatistics(StatisticsLog *statistics_log) const {
for (int statistic = MIN_STAT; statistic < MAX_STAT; ++statistic) {
statistics_log->LogStat(kStatisticNames[statistic], stats_[statistic]);
}
}
void LoggingFilter::Reset() {
// Cleaner than memset?
for (int statistic = MIN_STAT; statistic < MAX_STAT; ++statistic) {
stats_[statistic] = 0;
}
}
} // namespace net_instaweb