Commit fa7e3348 by felix

添加log记录

parent 58841056
......@@ -17,28 +17,6 @@ class Contract {
$context['buildProperty'] = SearchDao::searchBuildProperty();
$context['room'] = SearchDao::searchRoom();
$params = array(
'signedDate' =>$_REQUEST['signedDate'],
'status' =>$_REQUEST['status'],
'area' =>$_REQUEST['area'],
'permitNumber' =>$_REQUEST['permitNumber'],
'managerId' =>$_REQUEST['managerId'],
'paymentMethod' =>$_REQUEST['paymentMethod'],
'codicil' =>$_REQUEST['codicil'],
'oName' =>$_REQUEST['oName'],
'oID' =>$_REQUEST['oID'],
'oBroker' =>$_REQUEST['oBroker'],
'oAddress' =>$_REQUEST['oAddress'],
'oMoney' =>$_REQUEST['oMoney'],
'oPayBack' =>$_REQUEST['oPayBack'],
'cName' =>$_REQUEST['cName'],
'cID' =>$_REQUEST['cID'],
'cBroker' =>$_REQUEST['cBroker'],
'cAddress' =>$_REQUEST['cAddress'],
'cMoney' =>$_REQUEST['cMoney'],
'cPayBack' =>$_REQUEST['cPayBack']
);
if($type==1){
$wpdb->query("START TRANSACTION");
$prefix = "新增";
......@@ -49,7 +27,7 @@ class Contract {
if(!is_numeric($result)){
$wpdb->query("ROLLBACK");
$context["error"] = $result;
print_r($result);
echo $result;
echo $prefix."合同失败";
}else{
$wpdb->query("COMMIT");
......@@ -59,9 +37,13 @@ class Contract {
}else if(isset($_GET['edit'])){
$id = $_REQUEST["id"];
$context['result'] = ContractDao::searchContract($id);
$context["consultant"] = CommissionDao::search_commission_consultant($_GET["id"]);
$context["commission"] = CommissionDao::search_tospur_commission($_GET["id"]);
$context["commissionLog"] = CommissionDao::search_commission_log($context["commission"]->id);
$context["consultant"] = CommissionDao::search_commission_consultant($id);
$context["commission"] = CommissionDao::search_tospur_commission($id);
$commissionIds = array();
foreach($context["commission"] as $item){
$commissionIds[] = $item->id;
}
$context["commissionLog"] = CommissionDao::search_commission_log(implode(",",$commissionIds));
}
Timber::render("contract.html",$context);
}
......@@ -88,6 +70,7 @@ class Contract {
'cMoney' =>$_REQUEST['cMoney'],
'cPayBack' =>$_REQUEST['cPayBack']
);
$commissionType = array();
if(isset($_REQUEST["id"])){
$result = ContractDao::update($_REQUEST["id"],$params);
if(!is_numeric($result)){
......@@ -103,7 +86,8 @@ class Contract {
if(!is_numeric($result)){
return $result;
}
$commissionId = $_REQUEST['commissionId'];
$commissionType['buy'] = $_REQUEST['commissionId_buy'];
$commissionType['sell'] = $_REQUEST['commissionId_sell'];
}else{
$params['business'] = $_REQUEST['businessId'];
$params['houseNumber'] = $_REQUEST['houseNumber'];
......@@ -124,12 +108,12 @@ class Contract {
if($_REQUEST['type'] > 1){
$pre = "CJCZ";
}
$contractId = $pre.str_pad($result,6,'0',STR_PAD_LEFT);
$result = ContractDao::setContractId($result,$contractId);
$contractNumber = $pre.str_pad($result,6,'0',STR_PAD_LEFT);
$contractId = $result;
$result = ContractDao::setContractId($result,$contractNumber);
if(!is_numeric($result)){
return $result;
}
$contractId = $result;
//二手房、租房创建合同时修改房源的状态
if(intval($_REQUEST['businessId']) >=1 ){
$result = HouseDao::updateStatus(-1,$params['houseId']);
......@@ -137,29 +121,49 @@ class Contract {
return $result;
}
}
$commissionParams = array(
"intent" => $_REQUEST["intent"],
"accounts" => $_REQUEST["accounts"],
$buyCommission = $_REQUEST['buy'];
$buyCommissionParams = array(
"accounts" => $buyCommission["accounts"],
"type" => $_REQUEST["businessType"],
"contractId" => $contractId,
"consultantId" => $_REQUEST["consultantId"]
"consultantId" => $buyCommission["consultantId"],
"ioType" => 0
);
$result = CommissionDao::insert_touspur_commission($commissionParams);
$result = CommissionDao::insert_touspur_commission($buyCommissionParams);
if(!is_numeric($result)){
return $result;
}
$commissionId = $result;
$commissionType['buy'] = $result;
$sellCommission = $_REQUEST['sell'];
$sellCommissionParams = array(
"accounts" => $sellCommission["accounts"],
"type" => $_REQUEST["businessType"],
"contractId" => $contractId,
"consultantId" => $sellCommission["consultantId"],
"ioType" => 1
);
$result = CommissionDao::insert_touspur_commission($sellCommissionParams);
if(!is_numeric($result)){
return $result;
}
$commissionType['sell'] = $result;
}
if(isset( $_POST["log"])) {
foreach ($_POST["log"] as $value) {
foreach ($_POST["log"] as $key => $value) {
$commissionId = $commissionType[$key];
foreach($value as $item){
$logParams = array(
"commissionId" => $commissionId,
"time" => $value["time"],
"paid" => $value["paid"]
"time" => $item["time"],
"paid" => $item["paid"]
);
$logRes = CommissionDao::insert_commission_log($logParams);
$result = CommissionDao::insert_commission_log($logParams);
if(!is_numeric($result)){
return $result;
}
}
return $logRes;
};
}
return $result;
}
......
<?php
if (!class_exists('WP_List_Table')) {
require_once(ABSPATH . 'wp-admin/includes/class-wp-list-table.php');
}
class QuotaMonthList extends WP_List_Table{
function column_default($item, $column_name)
{
switch($column_name){
case "quota":
return "<input type='text' name='".$item["id"]."' value='".$item["quota"]."'><button type='button' class='button action'>修改</button>";
break;
default:
return $item[$column_name];
}
}
function get_columns()
{
$columns['year'] = '年份';
$columns['month'] = '月份';
$columns['name'] = '姓名';
$columns['quota'] = '目标业绩';
return $columns;
}
function get_views(){
global $wpdb;
$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
$current_url = remove_query_arg( array( 'paged','type'), $current_url );
$sql = "select COUNT(*) as totle,COUNT(NULLIF(quota is not null, false)) as isset,COUNT(NULLIF(quota is null, false)) as unset from ".Config::TOSPUR_CONSULTANT." tc
left join ".Config::TOSPUR_QUOTA_TABLE." tq on tq.consultantId = tc.id and tq.year = %d and tq.month = %d
where subsidiaryId = %d";
$result = $wpdb->get_row($wpdb->prepare($sql,$_REQUEST["year"],$_REQUEST["month"],$_REQUEST["oid"]));
return array(
"all" => '<a href="'.$current_url.'"'.(isset($_REQUEST["type"])?"":'class="current"').'>全部<span class="count">('.$result->totle.')</span></a>',
"isset" => '<a href="'.$current_url.'&type=2" '.($_REQUEST["type"]==2?'class="current"':"").'>已设置业绩<span class="count">('.$result->isset.')</span></a>',
"unset" => '<a href="'.$current_url.'&type=1" '.($_REQUEST["type"]==1?'class="current"':"").'>未设置业绩<span class="count">('.$result->unset.')</span></a>'
);
}
function prepare_items()
{
global $wpdb;
$per_page = 20;
$columns = $this->get_columns();
$hidden = array();
$this->_column_headers = array($columns, $hidden);
$data = array();
if(isset($_REQUEST["year"]) && isset($_REQUEST["month"]) && isset($_REQUEST["oid"])){
$sql = "select tc.id,name,IFNULL(quota,0) as quota from ".Config::TOSPUR_CONSULTANT." tc
left join ".Config::TOSPUR_QUOTA_TABLE." tq on tq.consultantId = tc.id and tq.year = %d and tq.month = %d
where subsidiaryId = %d";
if(isset($_REQUEST['type'])){
$type = $_REQUEST['type'];
$sql .= " and quota is";
if($type == 2){
$sql .= " not";
}
$sql .=" null";
}
$result = $wpdb->get_results($wpdb->prepare($sql,$_REQUEST["year"],$_REQUEST["month"],$_REQUEST["oid"]));
foreach($result as $key => $value){
$data[$key] = array(
'id' => $value->id,
'year' => $_REQUEST["year"],
'month' => $_REQUEST["month"],
'name' => $value->name,
'quota' => $value->quota
);
}
}
$current_page = $this->get_pagenum();
$total_items = count($data);
$data = array_slice($data, (($current_page - 1) * $per_page), $per_page);
$this->items = $data;
$this->set_pagination_args(array(
'total_items' => $total_items, //WE have to calculate the total number of items
'per_page' => $per_page, //WE have to determine how many items to show on a page
'total_pages' => ceil($total_items / $per_page) //WE have to calculate the total number of pages
));
}
public static function replaceQuota(){
$result = QuotaDao::replace($_REQUEST["year"],$_REQUEST["month"],$_REQUEST["id"],$_REQUEST["price"]);
$res = array(
"code"=>200,
"msg"=>$result
);
if(!is_numeric($result)){
$res["code"] = 500;
}
wp_send_json($res);
}
}
\ No newline at end of file
<?php
if (!class_exists('WP_List_Table')) {
require_once(ABSPATH . 'wp-admin/includes/class-wp-list-table.php');
}
class QuotaYearList extends WP_List_Table
{
function __construct()
{
}
function column_default($item, $column_name)
{
return '<a href="' . admin_url('admin.php?page=quotaList&edit=true&year='. $item['year'] .'&month=' . $item['month'] . '&oid='. $item['oid']) .'&name='. $item['name'] .'">' . $item[$column_name] . '</a>';
}
function get_columns()
{
$columns['year'] = '年份';
$columns['month'] = '月份';
$columns['name'] = '分店名';
$columns['totle'] = '分店总目标';
return $columns;
}
function prepare_items()
{
global $wpdb;
$per_page = 12;
$columns = $this->get_columns();
$hidden = array();
$this->_column_headers = array($columns, $hidden);
$data = array();
if(isset($_REQUEST["year"]) && isset($_REQUEST["oid"])){
$sql = "select *, month,sum(quota) as quota from ".Config::TOSPUR_QUOTA_TABLE." where consultantId in(select id from ".Config::TOSPUR_CONSULTANT."
where subsidiaryId = %d) and year = %d group by year,month;";
$result = $wpdb->get_results($wpdb->prepare($sql,$_REQUEST["oid"],$_REQUEST["year"]));
$name = $wpdb->get_var($wpdb->prepare("select Name from tospur_organization where id = %d;",$_REQUEST["oid"]));
$j = 0;
for($i = 1;$i<=12;$i++){
$item = $result[$j];
$totle = 0;
if($item->month==$i){
$totle = $item->quota;
$j++;
}
$data[$i] = array(
'oid' => $_REQUEST["oid"],
'year' => $_REQUEST["year"],
'month' => $i,
'name' => $name,
'totle' => $totle."元"
);
}
}
$current_page = $this->get_pagenum();
$total_items = count($data);
$data = array_slice($data, (($current_page - 1) * $per_page), $per_page);
$this->items = $data;
$this->set_pagination_args(array(
'total_items' => $total_items, //WE have to calculate the total number of items
'per_page' => $per_page, //WE have to determine how many items to show on a page
'total_pages' => 1 //WE have to calculate the total number of pages
));
}
function showHtml(){
$context = array();
$context['req'] = $_REQUEST;
if(isset($_REQUEST['edit'])){
$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
$current_url = remove_query_arg( array( 'paged'), $current_url );
$context['current_url'] = $current_url;
Timber::render("quotaMonthList.html",$context);
}else{
Timber::render("quotaYearList.html",$context);
}
}
function displayMonthTable(){
$_SERVER['REQUEST_URI'] = remove_query_arg( '_wp_http_referer', $_SERVER['REQUEST_URI'] );
$quotaMonthList = new QuotaMonthList();
$quotaMonthList->prepare_items();
$quotaMonthList->views();
$quotaMonthList->display();
}
function displayYearTable()
{
$_SERVER['REQUEST_URI'] = remove_query_arg( '_wp_http_referer', $_SERVER['REQUEST_URI'] );
$quotaYearList = new QuotaYearList();
$quotaYearList->prepare_items();
$quotaYearList->display();
}
}
\ No newline at end of file
......@@ -176,9 +176,9 @@ class consultantScoreList extends WP_List_Table
function add_consultant_score_menu()
{
add_menu_page('置业顾问评分', '置业顾问评分', 'moderate_comments', 'consultant_score', 'consultant_score_page', 'dashicons-menu', 26);
}
add_action('admin_menu', 'add_consultant_score_menu');
function consultant_score_page()
{
......
......@@ -221,7 +221,8 @@ class newHouseList extends WP_List_Table
$sql = $sql ." order by ".$orderby." ".$order;
}
$result = $wpdb->get_results($wpdb->prepare($sql, $params));
$result = DBManager::get_results($wpdb->prepare($sql, $params));
$data = array();
foreach ($result as $key => $value) {
$data[$key] = array(
......
<div class="wrap">
<h2>{{req.name}}{{req.year}}年{{req.month}}月业绩列表</h2>
{{function("QuotaYearList::displayMonthTable")}}
</div>
<script>
$(document).ready(function () {
$("#the-list").on("click","td > .button.action",function(){
var price = $(this).prev().val();
var id = $(this).prev().attr("name");
var params = {
action:"replaceQuota",
year:{{req.year}},
month:{{req.month}},
id:id,
price:price
};
$.ajax({
type: "post",
url: "admin-ajax.php",
data: params,
success:function(json){
if(json.code == 200)
alert("设置业绩目标成功");
else
alert(json.msg);
}
});
});
});
</script>
\ No newline at end of file
<div class="wrap">
<h2>业绩列表</h2>
<form method="get">
<input type="hidden" name="page" value="quotaList">
<div id="search_form">
<select name="year" id="year">
<option value="2015">2015</option>
<option value="2016">2016</option>
</select>
<input name="oid" type="text" id="oid" />
<input type="submit" id="submit" class="button action" value="搜索">
<!--
<select name="month" id="month">
<option value="1">一月</option>
<option value="2">二月</option>
<option value="3">三月</option>
<option value="4">四月</option>
<option value="5">五月</option>
<option value="6">六月</option>
<option value="7">七月</option>
<option value="8">八月</option>
<option value="9">九月</option>
<option value="10">十月</option>
<option value="11">十一月</option>
<option value="12">十二月</option>
</select>
-->
</div>
</form>
{{function("QuotaYearList::displayYearTable")}}
</div>
<script>
$(document).ready(function () {
{% if req %}
$("#year").val({{req.year}});
$("#oid").val({{req.oid}});
{% endif %}
});
</script>
\ No newline at end of file
......@@ -30,6 +30,7 @@ class Config {
const TOSPUR_CONTRACT = 'tospur_contract';
const TOSPUR_COMMISSION = 'tospur_commission';
const TOSPUR_COMMISSION_LOG = 'tospur_commission_log';
const TOSPUR_QUOTA_TABLE = 'tospur_quota';
//sync url
......
......@@ -22,26 +22,28 @@ class CommissionDao{
public static function search_commission_consultant($contractId){
global $wpdb;
$sql = "select consultantId,imageUrl,name from ".Config::TOSPUR_COMMISSION." tcom
left join (select id,imageUrl,name from ".Config::TOSPUR_CONSULTANT.") tct
on tcom.consultantId = tct.id where tcom.contractId = %d";
$result = $wpdb->get_row($wpdb->prepare($sql,$contractId));
$sql = " select consultantId,imageUrl,name,branchName,ioType from ".Config::TOSPUR_COMMISSION." tcom
left join (SELECT tct.id,imageUrl,tct.name,ton.name as branchName from ".Config::TOSPUR_CONSULTANT." tct
left JOIN ".Config::TOSPUR_ORGANIZATION_TABLE." ton on ton.id = tct.subsidiaryId) tc
on tcom.consultantId = tc.id where tcom.contractId = %d order by ioType;";
$result = $wpdb->get_results($wpdb->prepare($sql,$contractId));
return $result;
}
public static function search_commission_log($commissionId){
public static function search_commission_log($commissionIds){
global $wpdb;
$sql = "select id,time,paid from ".Config::TOSPUR_COMMISSION_LOG."
where commissionId = %d";
$result = $wpdb->get_results($wpdb->prepare($sql,$commissionId));
$sql = " SELECT tcl.id,time,paid,ioType from tospur_commission_log tcl
left join tospur_commission tc on tc.id = tcl.commissionId
where tcl.commissionId in (".$commissionIds.");";
$result = $wpdb->get_results($sql);
return $result;
}
public static function search_tospur_commission($contractId){
global $wpdb;
$sql = "select id,intent,accounts,type from ".Config::TOSPUR_COMMISSION."
$sql = "select id,accounts,type from ".Config::TOSPUR_COMMISSION."
where contractId = %d";
$result = $wpdb->get_row($wpdb->prepare($sql,$contractId));
$result = $wpdb->get_results($wpdb->prepare($sql,$contractId));
return $result;
}
}
......@@ -4,11 +4,12 @@ class ContractDao {
public static function insert($params){
global $wpdb;
$wpdb->insert(Config::TOSPUR_CONTRACT,$params);
if($wpdb->insert_id){
return $wpdb->insert_id;
}
if($wpdb->last_error){
return $wpdb->last_error;
}
print_r($wpdb->last_error);
return $wpdb->insert_id;
}
public static function setContractId($id,$contractId){
global $wpdb;
......
<?php
require_once(PLUGIN_DIR . 'lib/php4log/Logger.php');
class DBManager {
public static function query($sql){
global $wpdb;
$result = $wpdb->query($sql);
print_r($result->last_query);
DBManager::getLog()->info($wpdb->last_query);
if($result->last_error){
DBManager::getLog()->error($wpdb->last_error);
return $result->last_error;
}
return $result;
}
public static function get_results($sql){
global $wpdb;
$result = $wpdb->get_results($sql);
DBManager::getLog()->info($wpdb->last_query);
if($result->last_error){
DBManager::getLog()->error($wpdb->last_error);
return $result->last_error;
}
return $result;
}
public static function getLog(){
$config = PLUGIN_DIR . 'appender_pdo.properties';
$logger = Logger::configure($config);
$log = Logger::getLogger('log');
return $log;
}
}
\ No newline at end of file
<?php
class QuotaDao {
public static function replace($year,$month,$consultantId,$quota){
global $wpdb;
$result = $wpdb->replace(Config::TOSPUR_QUOTA_TABLE,array(
"year" => $year,
"month" => $month,
"consultantId" => $consultantId,
"quota" => $quota
),array(
"%d",
"%d",
"%d",
"%d"
));
if($wpdb->last_error)
return $wpdb->last_error;
return $result;
}
}
\ No newline at end of file
......@@ -126,12 +126,12 @@ class SearchDao
wp_send_json(SearchDao::searchOrganization($_GET['parentId']));
}
public static function searchOrganization($parentId = NULL)
public static function searchOrganization($parentId = 1)
{
global $wpdb;
$where = " where 1=1 ";
if ($parentId != NULL) {
$where .= " and ParentId =" . $parentId;
$where .= " and ParentId = %d";
}
$result = $wpdb->get_results($wpdb->prepare('select Id as id,Name as name from ' . Config::TOSPUR_ORGANIZATION_TABLE . $where, $parentId));
return $result;
......@@ -195,7 +195,7 @@ class SearchDao
$orderbySql = " order by th.creattime DESC";
}
$sql = "select th.id,th.house_type,th.name,th.latest_news,th.address,th.average_price,th.community_name,th.covered_area,th.total_price,th.decoration,th.rent,".
"ti.path,dr.literal,th.house_number,dbp.bp_literal,(SELECT GROUP_CONCAT(left(tt.name,3)) from ".Config::A_HOUSE_TAG_TABLE." aht".
"ti.path,dr.literal,th.house_number,dbp.bp_literal,th.owner_name,th.owner_phone,(SELECT GROUP_CONCAT(left(tt.name,3)) from ".Config::A_HOUSE_TAG_TABLE." aht".
" LEFT JOIN ".Config::TOSPUR_TAG_TABLE." tt on tt.id = aht.tag_id".
" where aht.house_id = th.id) as tags from ".Config::TOSPUR_HOUSE_TABLE." th".
$addSql.
......@@ -295,7 +295,9 @@ class SearchDao
public static function searchConsultant($consulCityId = NULL,$consultantName = NULL){
global $wpdb;
$sql = "select id,name,imageUrl from ".Config::TOSPUR_CONSULTANT." where 1=1";
$sql = "select tc.id,tc.name,imageUrl,tor.Name as branchName from ".Config::TOSPUR_CONSULTANT." tc
LEFT JOIN ".Config::TOSPUR_ORGANIZATION_TABLE." tor on tc.subsidiaryId = tor.Id
where 1=1";
$params = array();
if($consulCityId != NULL){
$params[] = $consulCityId;
......
......@@ -41,7 +41,10 @@ class TCSync {
'cityId' => $item['CityId'],
'imageUrl' => $item['ImageUrl'],
'mobile' => $item['Mobile'],
'name' => $item['Name']
'name' => $item['Name'],
'subsidiaryId' => $item['SubsidiaryId'],
'filedNameId' => $item['FiledNameId'],
'filedName' => $item['FiledName']
);
$wpdb->query(TCSync::create_insert_update_sql(Config::TOSPUR_CONSULTANT,$info,array('id')));
}
......
log4php.rootLogger = DEBUG, log
log4php.appender.log = LoggerAppenderPDO
log4php.appender.log.user = root
log4php.appender.log.password = 111111
log4php.appender.log.dsn = "mysql:host=localhost;dbname=test"
log4php.appender.log.table = log4php_log
log4php.appender.log.insertSql = "INSERT INTO log4php_log (timestamp, logger, level, message, thread, file, line) VALUES (?,?,?,?,?,?,?)"
log4php.appender.log.insertPattern = "%date{Y-m-d H:i:s},%c,%p,%m, %t,%F,%L"
......@@ -19,6 +19,8 @@ function tospur_init()
require_once(PLUGIN_DIR . 'Dao/TospurDao.php');
require_once(PLUGIN_DIR . 'Dao/CustomerTrackingDao.php');
require_once(PLUGIN_DIR . 'Dao/CustomerDao.php');
require_once(PLUGIN_DIR . 'Dao/QuotaDao.php');
require_once(PLUGIN_DIR . 'Dao/DBManager.php');
require_once(PLUGIN_DIR . 'Admin/House.php');
require_once(PLUGIN_DIR . 'Admin/customer.php');
require_once(PLUGIN_DIR . 'Admin/customerList.php');
......@@ -29,7 +31,10 @@ function tospur_init()
require_once(PLUGIN_DIR . 'Admin/rentHouseList.php');
require_once(PLUGIN_DIR . 'Admin/customer.php');
require_once(PLUGIN_DIR . 'Admin/customerList.php');
require_once(PLUGIN_DIR . 'Admin/customerTrackingList.php'); require_once(PLUGIN_DIR . 'Admin/feature.php');
require_once(PLUGIN_DIR . 'Admin/customerTrackingList.php');
require_once(PLUGIN_DIR . 'Admin/QuotaYearList.php');
require_once(PLUGIN_DIR . 'Admin/QuotaMonthList.php');
require_once(PLUGIN_DIR . 'Admin/feature.php');
require_once(PLUGIN_DIR . 'Admin/introduction.php');
require_once(PLUGIN_DIR . 'Admin/Contract.php');
require_once(PLUGIN_DIR . 'Admin/consultant_score.php');
......@@ -137,6 +142,8 @@ function tospur_ajax_set()
add_action('wp_ajax_nopriv_submit_introduction', 'introduction::ajax_submit_introduction');
add_action('wp_ajax_searchCustomerByNameOrPhone', 'CustomerDao::searchCustomerByNameOrPhone');
add_action('wp_ajax_nopriv_searchCustomerByNameOrPhone', 'CustomerDao::searchCustomerByNameOrPhone');
add_action('wp_ajax_replaceQuota', 'QuotaMonthList::replaceQuota');
//标签和特色
add_action('wp_ajax_searchTagOrFeature', 'SearchDao::ajax_searchTagOrFeature');
add_action('wp_ajax_nopriv_searchTagOrFeature', 'SearchDao::ajax_searchTagOrFeature');
......@@ -192,6 +199,8 @@ function reset_menu()
add_submenu_page('customerList', '新增客户', '新增客户', 'edit_published_posts', 'customer', 'customer::customer_html');
add_menu_page('签约—房客跟进', '签约—房客跟进', 'edit_published_posts', 'customerTrackingList', 'function_customerTrackingList', 'dashicons-menu', 12);
add_menu_page('收佣管理','收佣管理', 'edit_published_posts', 'commissionManage', 'commissionManage::commissionManage_html', 'dashicons-menu', 13);
add_menu_page('置业顾问评分', '置业顾问评分', 'moderate_comments', 'consultant_score', 'consultant_score_page', 'dashicons-menu', 14);
add_submenu_page('consultant_score', '置业顾问业绩', '置业顾问业绩', 'edit_published_posts', 'quotaList', 'QuotaYearList::showHtml');
add_menu_page('添加标签', '添加标签', 'edit_published_posts', 'add_tag', 'feature::add_feature_html', 'dashicons-menu');
add_menu_page('添加特色', '添加特色', 'edit_published_posts', 'add_feature', 'feature::add_feature_html', 'dashicons-menu');
add_menu_page("同步数据", "同步数据", "manage_options", "sync", "TCSyncView::display", 'dashicons-menu');
......
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* @package log4php
*/
/**
* Abstract class that defines output logs strategies.
*
* @version $Revision: 1374777 $
* @package log4php
*/
abstract class LoggerAppender extends LoggerConfigurable {
/**
* Set to true when the appender is closed. A closed appender will not
* accept any logging requests.
* @var boolean
*/
protected $closed = false;
/**
* The first filter in the filter chain.
* @var LoggerFilter
*/
protected $filter;
/**
* The appender's layout. Can be null if the appender does not use
* a layout.
* @var LoggerLayout
*/
protected $layout;
/**
* Appender name. Used by other components to identify this appender.
* @var string
*/
protected $name;
/**
* Appender threshold level. Events whose level is below the threshold
* will not be logged.
* @var LoggerLevel
*/
protected $threshold;
/**
* Set to true if the appender requires a layout.
*
* True by default, appenders which do not use a layout should override
* this property to false.
*
* @var boolean
*/
protected $requiresLayout = true;
/**
* Default constructor.
* @param string $name Appender name
*/
public function __construct($name = '') {
$this->name = $name;
if ($this->requiresLayout) {
$this->layout = $this->getDefaultLayout();
}
}
public function __destruct() {
$this->close();
}
/**
* Returns the default layout for this appender. Can be overriden by
* derived appenders.
*
* @return LoggerLayout
*/
public function getDefaultLayout() {
return new LoggerLayoutSimple();
}
/**
* Adds a filter to the end of the filter chain.
* @param LoggerFilter $filter add a new LoggerFilter
*/
public function addFilter($filter) {
if($this->filter === null) {
$this->filter = $filter;
} else {
$this->filter->addNext($filter);
}
}
/**
* Clears the filter chain by removing all the filters in it.
*/
public function clearFilters() {
$this->filter = null;
}
/**
* Returns the first filter in the filter chain.
* The return value may be <i>null</i> if no is filter is set.
* @return LoggerFilter
*/
public function getFilter() {
return $this->filter;
}
/**
* Returns the first filter in the filter chain.
* The return value may be <i>null</i> if no is filter is set.
* @return LoggerFilter
*/
public function getFirstFilter() {
return $this->filter;
}
/**
* Performs threshold checks and invokes filters before delegating logging
* to the subclass' specific <i>append()</i> method.
* @see LoggerAppender::append()
* @param LoggerLoggingEvent $event
*/
public function doAppend(LoggerLoggingEvent $event) {
if($this->closed) {
return;
}
if(!$this->isAsSevereAsThreshold($event->getLevel())) {
return;
}
$filter = $this->getFirstFilter();
while($filter !== null) {
switch ($filter->decide($event)) {
case LoggerFilter::DENY: return;
case LoggerFilter::ACCEPT: return $this->append($event);
case LoggerFilter::NEUTRAL: $filter = $filter->getNext();
}
}
$this->append($event);
}
/**
* Sets the appender layout.
* @param LoggerLayout $layout
*/
public function setLayout($layout) {
if($this->requiresLayout()) {
$this->layout = $layout;
}
}
/**
* Returns the appender layout.
* @return LoggerLayout
*/
public function getLayout() {
return $this->layout;
}
/**
* Configurators call this method to determine if the appender
* requires a layout.
*
* <p>If this method returns <i>true</i>, meaning that layout is required,
* then the configurator will configure a layout using the configuration
* information at its disposal. If this method returns <i>false</i>,
* meaning that a layout is not required, then layout configuration will be
* skipped even if there is available layout configuration
* information at the disposal of the configurator.</p>
*
* <p>In the rather exceptional case, where the appender
* implementation admits a layout but can also work without it, then
* the appender should return <i>true</i>.</p>
*
* @return boolean
*/
public function requiresLayout() {
return $this->requiresLayout;
}
/**
* Retruns the appender name.
* @return string
*/
public function getName() {
return $this->name;
}
/**
* Sets the appender name.
* @param string $name
*/
public function setName($name) {
$this->name = $name;
}
/**
* Returns the appender's threshold level.
* @return LoggerLevel
*/
public function getThreshold() {
return $this->threshold;
}
/**
* Sets the appender threshold.
*
* @param LoggerLevel|string $threshold Either a {@link LoggerLevel}
* object or a string equivalent.
* @see LoggerOptionConverter::toLevel()
*/
public function setThreshold($threshold) {
$this->setLevel('threshold', $threshold);
}
/**
* Checks whether the message level is below the appender's threshold.
*
* If there is no threshold set, then the return value is always <i>true</i>.
*
* @param LoggerLevel $level
* @return boolean Returns true if level is greater or equal than
* threshold, or if the threshold is not set. Otherwise returns false.
*/
public function isAsSevereAsThreshold($level) {
if($this->threshold === null) {
return true;
}
return $level->isGreaterOrEqual($this->getThreshold());
}
/**
* Prepares the appender for logging.
*
* Derived appenders should override this method if option structure
* requires it.
*/
public function activateOptions() {
$this->closed = false;
}
/**
* Forwards the logging event to the destination.
*
* Derived appenders should implement this method to perform actual logging.
*
* @param LoggerLoggingEvent $event
*/
abstract protected function append(LoggerLoggingEvent $event);
/**
* Releases any resources allocated by the appender.
*
* Derived appenders should override this method to perform proper closing
* procedures.
*/
public function close() {
$this->closed = true;
}
/** Triggers a warning for this logger with the given message. */
protected function warn($message) {
$id = get_class($this) . (empty($this->name) ? '' : ":{$this->name}");
trigger_error("log4php: [$id]: $message", E_USER_WARNING);
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* @package log4php
*/
/**
* Pool implmentation for LoggerAppender instances.
*
* The pool is used when configuring log4php. First all appender instances
* are created in the pool. Afterward, they are linked to loggers, each
* appender can be linked to multiple loggers. This makes sure duplicate
* appenders are not created.
*
* @version $Revision: 1350602 $
* @package log4php
*/
class LoggerAppenderPool {
/** Holds appenders indexed by their name */
public static $appenders = array();
/**
* Adds an appender to the pool.
* The appender must be named for this operation.
* @param LoggerAppender $appender
*/
public static function add(LoggerAppender $appender) {
$name = $appender->getName();
if(empty($name)) {
trigger_error('log4php: Cannot add unnamed appender to pool.', E_USER_WARNING);
return;
}
if (isset(self::$appenders[$name])) {
trigger_error("log4php: Appender [$name] already exists in pool. Overwriting existing appender.", E_USER_WARNING);
}
self::$appenders[$name] = $appender;
}
/**
* Retrieves an appender from the pool by name.
* @param string $name Name of the appender to retrieve.
* @return LoggerAppender The named appender or NULL if no such appender
* exists in the pool.
*/
public static function get($name) {
return isset(self::$appenders[$name]) ? self::$appenders[$name] : null;
}
/**
* Removes an appender from the pool by name.
* @param string $name Name of the appender to remove.
*/
public static function delete($name) {
unset(self::$appenders[$name]);
}
/**
* Returns all appenders from the pool.
* @return array Array of LoggerAppender objects.
*/
public static function getAppenders() {
return self::$appenders;
}
/**
* Checks whether an appender exists in the pool.
* @param string $name Name of the appender to look for.
* @return boolean TRUE if the appender with the given name exists.
*/
public static function exists($name) {
return isset(self::$appenders[$name]);
}
/**
* Clears all appenders from the pool.
*/
public static function clear() {
self::$appenders = array();
}
}
\ No newline at end of file
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* @package log4php
*/
if (function_exists('__autoload')) {
trigger_error("log4php: It looks like your code is using an __autoload() function. log4php uses spl_autoload_register() which will bypass your __autoload() function and may break autoloading.", E_USER_WARNING);
}
spl_autoload_register(array('LoggerAutoloader', 'autoload'));
/**
* Class autoloader.
*
* @package log4php
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @version $Revision: 1394956 $
*/
class LoggerAutoloader {
/** Maps classnames to files containing the class. */
private static $classes = array(
// Base
'LoggerAppender' => '/LoggerAppender.php',
'LoggerAppenderPool' => '/LoggerAppenderPool.php',
'LoggerConfigurable' => '/LoggerConfigurable.php',
'LoggerConfigurator' => '/LoggerConfigurator.php',
'LoggerException' => '/LoggerException.php',
'LoggerFilter' => '/LoggerFilter.php',
'LoggerHierarchy' => '/LoggerHierarchy.php',
'LoggerLevel' => '/LoggerLevel.php',
'LoggerLocationInfo' => '/LoggerLocationInfo.php',
'LoggerLoggingEvent' => '/LoggerLoggingEvent.php',
'LoggerMDC' => '/LoggerMDC.php',
'LoggerNDC' => '/LoggerNDC.php',
'LoggerLayout' => '/LoggerLayout.php',
'LoggerReflectionUtils' => '/LoggerReflectionUtils.php',
'LoggerRoot' => '/LoggerRoot.php',
'LoggerThrowableInformation' => '/LoggerThrowableInformation.php',
// Appenders
'LoggerAppenderConsole' => '/appenders/LoggerAppenderConsole.php',
'LoggerAppenderDailyFile' => '/appenders/LoggerAppenderDailyFile.php',
'LoggerAppenderEcho' => '/appenders/LoggerAppenderEcho.php',
'LoggerAppenderFile' => '/appenders/LoggerAppenderFile.php',
'LoggerAppenderMail' => '/appenders/LoggerAppenderMail.php',
'LoggerAppenderMailEvent' => '/appenders/LoggerAppenderMailEvent.php',
'LoggerAppenderMongoDB' => '/appenders/LoggerAppenderMongoDB.php',
'LoggerAppenderNull' => '/appenders/LoggerAppenderNull.php',
'LoggerAppenderFirePHP' => '/appenders/LoggerAppenderFirePHP.php',
'LoggerAppenderPDO' => '/appenders/LoggerAppenderPDO.php',
'LoggerAppenderPhp' => '/appenders/LoggerAppenderPhp.php',
'LoggerAppenderRollingFile' => '/appenders/LoggerAppenderRollingFile.php',
'LoggerAppenderSocket' => '/appenders/LoggerAppenderSocket.php',
'LoggerAppenderSyslog' => '/appenders/LoggerAppenderSyslog.php',
// Configurators
'LoggerConfigurationAdapter' => '/configurators/LoggerConfigurationAdapter.php',
'LoggerConfigurationAdapterINI' => '/configurators/LoggerConfigurationAdapterINI.php',
'LoggerConfigurationAdapterPHP' => '/configurators/LoggerConfigurationAdapterPHP.php',
'LoggerConfigurationAdapterXML' => '/configurators/LoggerConfigurationAdapterXML.php',
'LoggerConfiguratorDefault' => '/configurators/LoggerConfiguratorDefault.php',
// Filters
'LoggerFilterDenyAll' => '/filters/LoggerFilterDenyAll.php',
'LoggerFilterLevelMatch' => '/filters/LoggerFilterLevelMatch.php',
'LoggerFilterLevelRange' => '/filters/LoggerFilterLevelRange.php',
'LoggerFilterStringMatch' => '/filters/LoggerFilterStringMatch.php',
// Helpers
'LoggerFormattingInfo' => '/helpers/LoggerFormattingInfo.php',
'LoggerOptionConverter' => '/helpers/LoggerOptionConverter.php',
'LoggerPatternParser' => '/helpers/LoggerPatternParser.php',
'LoggerUtils' => '/helpers/LoggerUtils.php',
// Pattern converters
'LoggerPatternConverter' => '/pattern/LoggerPatternConverter.php',
'LoggerPatternConverterClass' => '/pattern/LoggerPatternConverterClass.php',
'LoggerPatternConverterCookie' => '/pattern/LoggerPatternConverterCookie.php',
'LoggerPatternConverterDate' => '/pattern/LoggerPatternConverterDate.php',
'LoggerPatternConverterEnvironment' => '/pattern/LoggerPatternConverterEnvironment.php',
'LoggerPatternConverterFile' => '/pattern/LoggerPatternConverterFile.php',
'LoggerPatternConverterLevel' => '/pattern/LoggerPatternConverterLevel.php',
'LoggerPatternConverterLine' => '/pattern/LoggerPatternConverterLine.php',
'LoggerPatternConverterLiteral' => '/pattern/LoggerPatternConverterLiteral.php',
'LoggerPatternConverterLocation' => '/pattern/LoggerPatternConverterLocation.php',
'LoggerPatternConverterLogger' => '/pattern/LoggerPatternConverterLogger.php',
'LoggerPatternConverterMDC' => '/pattern/LoggerPatternConverterMDC.php',
'LoggerPatternConverterMessage' => '/pattern/LoggerPatternConverterMessage.php',
'LoggerPatternConverterMethod' => '/pattern/LoggerPatternConverterMethod.php',
'LoggerPatternConverterNDC' => '/pattern/LoggerPatternConverterNDC.php',
'LoggerPatternConverterNewLine' => '/pattern/LoggerPatternConverterNewLine.php',
'LoggerPatternConverterProcess' => '/pattern/LoggerPatternConverterProcess.php',
'LoggerPatternConverterRelative' => '/pattern/LoggerPatternConverterRelative.php',
'LoggerPatternConverterRequest' => '/pattern/LoggerPatternConverterRequest.php',
'LoggerPatternConverterServer' => '/pattern/LoggerPatternConverterServer.php',
'LoggerPatternConverterSession' => '/pattern/LoggerPatternConverterSession.php',
'LoggerPatternConverterSessionID' => '/pattern/LoggerPatternConverterSessionID.php',
'LoggerPatternConverterSuperglobal' => '/pattern/LoggerPatternConverterSuperglobal.php',
'LoggerPatternConverterThrowable' => '/pattern/LoggerPatternConverterThrowable.php',
// Layouts
'LoggerLayoutHtml' => '/layouts/LoggerLayoutHtml.php',
'LoggerLayoutPattern' => '/layouts/LoggerLayoutPattern.php',
'LoggerLayoutSerialized' => '/layouts/LoggerLayoutSerialized.php',
'LoggerLayoutSimple' => '/layouts/LoggerLayoutSimple.php',
'LoggerLayoutTTCC' => '/layouts/LoggerLayoutTTCC.php',
'LoggerLayoutXml' => '/layouts/LoggerLayoutXml.php',
// Renderers
'LoggerRendererDefault' => '/renderers/LoggerRendererDefault.php',
'LoggerRendererException' => '/renderers/LoggerRendererException.php',
'LoggerRendererMap' => '/renderers/LoggerRendererMap.php',
'LoggerRenderer' => '/renderers/LoggerRenderer.php',
);
/**
* Loads a class.
* @param string $className The name of the class to load.
*/
public static function autoload($className) {
if(isset(self::$classes[$className])) {
include dirname(__FILE__) . self::$classes[$className];
}
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* @package log4php
*/
/**
* A base class from which all classes which have configurable properties are
* extended. Provides a generic setter with integrated validation.
*
* @package log4php
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @version $Revision $
* @since 2.2
*/
abstract class LoggerConfigurable {
/** Setter function for boolean type. */
protected function setBoolean($property, $value) {
try {
$this->$property = LoggerOptionConverter::toBooleanEx($value);
} catch (Exception $ex) {
$value = var_export($value, true);
$this->warn("Invalid value given for '$property' property: [$value]. Expected a boolean value. Property not changed.");
}
}
/** Setter function for integer type. */
protected function setInteger($property, $value) {
try {
$this->$property = LoggerOptionConverter::toIntegerEx($value);
} catch (Exception $ex) {
$value = var_export($value, true);
$this->warn("Invalid value given for '$property' property: [$value]. Expected an integer. Property not changed.");
}
}
/** Setter function for LoggerLevel values. */
protected function setLevel($property, $value) {
try {
$this->$property = LoggerOptionConverter::toLevelEx($value);
} catch (Exception $ex) {
$value = var_export($value, true);
$this->warn("Invalid value given for '$property' property: [$value]. Expected a level value. Property not changed.");
}
}
/** Setter function for integer type. */
protected function setPositiveInteger($property, $value) {
try {
$this->$property = LoggerOptionConverter::toPositiveIntegerEx($value);
} catch (Exception $ex) {
$value = var_export($value, true);
$this->warn("Invalid value given for '$property' property: [$value]. Expected a positive integer. Property not changed.");
}
}
/** Setter for file size. */
protected function setFileSize($property, $value) {
try {
$this->$property = LoggerOptionConverter::toFileSizeEx($value);
} catch (Exception $ex) {
$value = var_export($value, true);
$this->warn("Invalid value given for '$property' property: [$value]. Expected a file size value. Property not changed.");
}
}
/** Setter function for numeric type. */
protected function setNumeric($property, $value) {
try {
$this->$property = LoggerOptionConverter::toNumericEx($value);
} catch (Exception $ex) {
$value = var_export($value, true);
$this->warn("Invalid value given for '$property' property: [$value]. Expected a number. Property not changed.");
}
}
/** Setter function for string type. */
protected function setString($property, $value, $nullable = false) {
if ($value === null) {
if($nullable) {
$this->$property= null;
} else {
$this->warn("Null value given for '$property' property. Expected a string. Property not changed.");
}
} else {
try {
$value = LoggerOptionConverter::toStringEx($value);
$this->$property = LoggerOptionConverter::substConstants($value);
} catch (Exception $ex) {
$value = var_export($value, true);
$this->warn("Invalid value given for '$property' property: [$value]. Expected a string. Property not changed.");
}
}
}
/** Triggers a warning. */
protected function warn($message) {
$class = get_class($this);
trigger_error("log4php: $class: $message", E_USER_WARNING);
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* @package log4php
*/
/**
* Interface for logger configurators.
*
* @package log4php
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @version $Revision: 1213710 $
* @since 2.2
*/
interface LoggerConfigurator
{
/**
* Configures log4php based on the given configuration.
*
* All configurators implementations must implement this interface.
*
* @param LoggerHierarchy $hierarchy The hierarchy on which to perform
* the configuration.
* @param mixed $input Either path to the config file or the
* configuration as an array.
*/
public function configure(LoggerHierarchy $hierarchy, $input = null);
}
\ No newline at end of file
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* @package log4php
*/
/**
* LoggerException class
*
* @version $Revision: 1334369 $
* @package log4php
*/
class LoggerException extends Exception {
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* @package log4php
*/
/**
* Users should extend this class to implement customized logging
* event filtering. Note that {@link LoggerCategory} and {@link LoggerAppender},
* the parent class of all standard
* appenders, have built-in filtering rules. It is suggested that you
* first use and understand the built-in rules before rushing to write
* your own custom filters.
*
* <p>This abstract class assumes and also imposes that filters be
* organized in a linear chain. The {@link #decide
* decide(LoggerLoggingEvent)} method of each filter is called sequentially,
* in the order of their addition to the chain.
*
* <p>The {@link decide()} method must return one
* of the integer constants {@link LoggerFilter::DENY},
* {@link LoggerFilter::NEUTRAL} or {@link LoggerFilter::ACCEPT}.
*
* <p>If the value {@link LoggerFilter::DENY} is returned, then the log event is
* dropped immediately without consulting with the remaining
* filters.
*
* <p>If the value {@link LoggerFilter::NEUTRAL} is returned, then the next filter
* in the chain is consulted. If there are no more filters in the
* chain, then the log event is logged. Thus, in the presence of no
* filters, the default behaviour is to log all logging events.
*
* <p>If the value {@link LoggerFilter::ACCEPT} is returned, then the log
* event is logged without consulting the remaining filters.
*
* <p>The philosophy of log4php filters is largely inspired from the
* Linux ipchains.
*
* @version $Revision: 1213283 $
* @package log4php
*/
abstract class LoggerFilter extends LoggerConfigurable {
/**
* The log event must be logged immediately without consulting with
* the remaining filters, if any, in the chain.
*/
const ACCEPT = 1;
/**
* This filter is neutral with respect to the log event. The
* remaining filters, if any, should be consulted for a final decision.
*/
const NEUTRAL = 0;
/**
* The log event must be dropped immediately without consulting
* with the remaining filters, if any, in the chain.
*/
const DENY = -1;
/**
* @var LoggerFilter Points to the next {@link LoggerFilter} in the filter chain.
*/
protected $next;
/**
* Usually filters options become active when set. We provide a
* default do-nothing implementation for convenience.
*/
public function activateOptions() {
}
/**
* Decide what to do.
* <p>If the decision is {@link LoggerFilter::DENY}, then the event will be
* dropped. If the decision is {@link LoggerFilter::NEUTRAL}, then the next
* filter, if any, will be invoked. If the decision is {@link LoggerFilter::ACCEPT} then
* the event will be logged without consulting with other filters in
* the chain.
*
* @param LoggerLoggingEvent $event The {@link LoggerLoggingEvent} to decide upon.
* @return integer {@link LoggerFilter::NEUTRAL} or {@link LoggerFilter::DENY}|{@link LoggerFilter::ACCEPT}
*/
public function decide(LoggerLoggingEvent $event) {
return self::NEUTRAL;
}
/**
* Adds a new filter to the filter chain this filter is a part of.
* If this filter has already and follow up filter, the param filter
* is passed on until it is the last filter in chain.
*
* @param $filter - the filter to add to this chain
*/
public function addNext($filter) {
if($this->next !== null) {
$this->next->addNext($filter);
} else {
$this->next = $filter;
}
}
/**
* Returns the next filter in this chain
* @return the next filter
*/
public function getNext() {
return $this->next;
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* @package log4php
*/
/**
* This class is specialized in retrieving loggers by name and also maintaining
* the logger hierarchy. The logger hierarchy is dealing with the several Log-Levels
* Logger can have. From log4j website:
*
* "A logger is said to be an ancestor of another logger if its name followed
* by a dot is a prefix of the descendant logger name. A logger is said to be
* a parent of a child logger if there are no ancestors between itself and the
* descendant logger."
*
* Child Loggers do inherit their Log-Levels from their Ancestors. They can
* increase their Log-Level compared to their Ancestors, but they cannot decrease it.
*
* <p>The casual user does not have to deal with this class directly.</p>
*
* <p>The structure of the logger hierarchy is maintained by the
* getLogger method. The hierarchy is such that children link
* to their parent but parents do not have any pointers to their
* children. Moreover, loggers can be instantiated in any order, in
* particular descendant before ancestor.</p>
*
* <p>In case a descendant is created before a particular ancestor,
* then it creates a provision node for the ancestor and adds itself
* to the provision node. Other descendants of the same ancestor add
* themselves to the previously created provision node.</p>
*
* @version $Revision: 1394956 $
* @package log4php
*/
class LoggerHierarchy {
/** Array holding all Logger instances. */
protected $loggers = array();
/**
* The root logger.
* @var RootLogger
*/
protected $root;
/**
* The logger renderer map.
* @var LoggerRendererMap
*/
protected $rendererMap;
/**
* Main level threshold. Events with lower level will not be logged by any
* logger, regardless of it's configuration.
* @var LoggerLevel
*/
protected $threshold;
/**
* Creates a new logger hierarchy.
* @param LoggerRoot $root The root logger.
*/
public function __construct(LoggerRoot $root) {
$this->root = $root;
$this->setThreshold(LoggerLevel::getLevelAll());
$this->rendererMap = new LoggerRendererMap();
}
/**
* Clears all loggers.
*/
public function clear() {
$this->loggers = array();
}
/**
* Check if the named logger exists in the hierarchy.
* @param string $name
* @return boolean
*/
public function exists($name) {
return isset($this->loggers[$name]);
}
/**
* Returns all the currently defined loggers in this hierarchy as an array.
* @return array
*/
public function getCurrentLoggers() {
return array_values($this->loggers);
}
/**
* Returns a named logger instance logger. If it doesn't exist, one is created.
*
* @param string $name Logger name
* @return Logger Logger instance.
*/
public function getLogger($name) {
if(!isset($this->loggers[$name])) {
$logger = new Logger($name);
$nodes = explode('.', $name);
$firstNode = array_shift($nodes);
// if name is not a first node but another first node is their
if($firstNode != $name and isset($this->loggers[$firstNode])) {
$logger->setParent($this->loggers[$firstNode]);
} else {
// if there is no father, set root logger as father
$logger->setParent($this->root);
}
// if there are more nodes than one
if(count($nodes) > 0) {
// find parent node
foreach($nodes as $node) {
$parentNode = "$firstNode.$node";
if(isset($this->loggers[$parentNode]) and $parentNode != $name) {
$logger->setParent($this->loggers[$parentNode]);
}
$firstNode .= ".$node";
}
}
$this->loggers[$name] = $logger;
}
return $this->loggers[$name];
}
/**
* Returns the logger renderer map.
* @return LoggerRendererMap
*/
public function getRendererMap() {
return $this->rendererMap;
}
/**
* Returns the root logger.
* @return LoggerRoot
*/
public function getRootLogger() {
return $this->root;
}
/**
* Returns the main threshold level.
* @return LoggerLevel
*/
public function getThreshold() {
return $this->threshold;
}
/**
* Returns true if the hierarchy is disabled for given log level and false
* otherwise.
* @return boolean
*/
public function isDisabled(LoggerLevel $level) {
return ($this->threshold->toInt() > $level->toInt());
}
/**
* Reset all values contained in this hierarchy instance to their
* default.
*
* This removes all appenders from all loggers, sets
* the level of all non-root loggers to <i>null</i>,
* sets their additivity flag to <i>true</i> and sets the level
* of the root logger to {@link LOGGER_LEVEL_DEBUG}.
*
* <p>Existing loggers are not removed. They are just reset.
*
* <p>This method should be used sparingly and with care as it will
* block all logging until it is completed.</p>
*/
public function resetConfiguration() {
$root = $this->getRootLogger();
$root->setLevel(LoggerLevel::getLevelDebug());
$this->setThreshold(LoggerLevel::getLevelAll());
$this->shutDown();
foreach($this->loggers as $logger) {
$logger->setLevel(null);
$logger->setAdditivity(true);
$logger->removeAllAppenders();
}
$this->rendererMap->reset();
LoggerAppenderPool::clear();
}
/**
* Sets the main threshold level.
* @param LoggerLevel $l
*/
public function setThreshold(LoggerLevel $threshold) {
$this->threshold = $threshold;
}
/**
* Shutting down a hierarchy will <i>safely</i> close and remove
* all appenders in all loggers including the root logger.
*
* The shutdown method is careful to close nested
* appenders before closing regular appenders. This is allows
* configurations where a regular appender is attached to a logger
* and again to a nested appender.
*
* @todo Check if the last paragraph is correct.
*/
public function shutdown() {
$this->root->removeAllAppenders();
foreach($this->loggers as $logger) {
$logger->removeAllAppenders();
}
}
/**
* Prints the current Logger hierarchy tree. Useful for debugging.
*/
public function printHierarchy() {
$this->printHierarchyInner($this->getRootLogger(), 0);
}
private function printHierarchyInner(Logger $current, $level) {
for ($i = 0; $i < $level; $i++) {
echo ($i == $level - 1) ? "|--" : "| ";
}
echo $current->getName() . "\n";
foreach($this->loggers as $logger) {
if ($logger->getParent() == $current) {
$this->printHierarchyInner($logger, $level + 1);
}
}
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* @package log4php
*/
/**
* Extend this abstract class to create your own log layout format.
*
* @version $Revision: 1213283 $
* @package log4php
*/
abstract class LoggerLayout extends LoggerConfigurable {
/**
* Activates options for this layout.
* Override this method if you have options to be activated.
*/
public function activateOptions() {
return true;
}
/**
* Override this method to create your own layout format.
*
* @param LoggerLoggingEvent
* @return string
*/
public function format(LoggerLoggingEvent $event) {
return $event->getRenderedMessage();
}
/**
* Returns the content type output by this layout.
* @return string
*/
public function getContentType() {
return "text/plain";
}
/**
* Returns the footer for the layout format.
* @return string
*/
public function getFooter() {
return null;
}
/**
* Returns the header for the layout format.
* @return string
*/
public function getHeader() {
return null;
}
/** Triggers a warning for this layout with the given message. */
protected function warn($message) {
trigger_error("log4php: [" . get_class($this) . "]: $message", E_USER_WARNING);
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* @package log4php
*/
/**
* Defines the minimum set of levels recognized by the system, that is
* <i>OFF</i>, <i>FATAL</i>, <i>ERROR</i>,
* <i>WARN</i>, <i>INFO</i>, <i>DEBUG</i> and
* <i>ALL</i>.
*
* <p>The <i>LoggerLevel</i> class may be subclassed to define a larger
* level set.</p>
*
* @version $Revision: 1379729 $
* @package log4php
* @since 0.5
*/
class LoggerLevel {
const OFF = 2147483647;
const FATAL = 50000;
const ERROR = 40000;
const WARN = 30000;
const INFO = 20000;
const DEBUG = 10000;
const TRACE = 5000;
const ALL = -2147483647;
/** Integer level value. */
private $level;
/** Contains a list of instantiated levels. */
private static $levelMap;
/** String representation of the level. */
private $levelStr;
/**
* Equivalent syslog level.
* @var integer
*/
private $syslogEquivalent;
/**
* Constructor
*
* @param integer $level
* @param string $levelStr
* @param integer $syslogEquivalent
*/
private function __construct($level, $levelStr, $syslogEquivalent) {
$this->level = $level;
$this->levelStr = $levelStr;
$this->syslogEquivalent = $syslogEquivalent;
}
/**
* Compares two logger levels.
*
* @param LoggerLevels $other
* @return boolean
*/
public function equals($other) {
if($other instanceof LoggerLevel) {
if($this->level == $other->level) {
return true;
}
} else {
return false;
}
}
/**
* Returns an Off Level
* @return LoggerLevel
*/
public static function getLevelOff() {
if(!isset(self::$levelMap[LoggerLevel::OFF])) {
self::$levelMap[LoggerLevel::OFF] = new LoggerLevel(LoggerLevel::OFF, 'OFF', LOG_ALERT);
}
return self::$levelMap[LoggerLevel::OFF];
}
/**
* Returns a Fatal Level
* @return LoggerLevel
*/
public static function getLevelFatal() {
if(!isset(self::$levelMap[LoggerLevel::FATAL])) {
self::$levelMap[LoggerLevel::FATAL] = new LoggerLevel(LoggerLevel::FATAL, 'FATAL', LOG_ALERT);
}
return self::$levelMap[LoggerLevel::FATAL];
}
/**
* Returns an Error Level
* @return LoggerLevel
*/
public static function getLevelError() {
if(!isset(self::$levelMap[LoggerLevel::ERROR])) {
self::$levelMap[LoggerLevel::ERROR] = new LoggerLevel(LoggerLevel::ERROR, 'ERROR', LOG_ERR);
}
return self::$levelMap[LoggerLevel::ERROR];
}
/**
* Returns a Warn Level
* @return LoggerLevel
*/
public static function getLevelWarn() {
if(!isset(self::$levelMap[LoggerLevel::WARN])) {
self::$levelMap[LoggerLevel::WARN] = new LoggerLevel(LoggerLevel::WARN, 'WARN', LOG_WARNING);
}
return self::$levelMap[LoggerLevel::WARN];
}
/**
* Returns an Info Level
* @return LoggerLevel
*/
public static function getLevelInfo() {
if(!isset(self::$levelMap[LoggerLevel::INFO])) {
self::$levelMap[LoggerLevel::INFO] = new LoggerLevel(LoggerLevel::INFO, 'INFO', LOG_INFO);
}
return self::$levelMap[LoggerLevel::INFO];
}
/**
* Returns a Debug Level
* @return LoggerLevel
*/
public static function getLevelDebug() {
if(!isset(self::$levelMap[LoggerLevel::DEBUG])) {
self::$levelMap[LoggerLevel::DEBUG] = new LoggerLevel(LoggerLevel::DEBUG, 'DEBUG', LOG_DEBUG);
}
return self::$levelMap[LoggerLevel::DEBUG];
}
/**
* Returns a Trace Level
* @return LoggerLevel
*/
public static function getLevelTrace() {
if(!isset(self::$levelMap[LoggerLevel::TRACE])) {
self::$levelMap[LoggerLevel::TRACE] = new LoggerLevel(LoggerLevel::TRACE, 'TRACE', LOG_DEBUG);
}
return self::$levelMap[LoggerLevel::TRACE];
}
/**
* Returns an All Level
* @return LoggerLevel
*/
public static function getLevelAll() {
if(!isset(self::$levelMap[LoggerLevel::ALL])) {
self::$levelMap[LoggerLevel::ALL] = new LoggerLevel(LoggerLevel::ALL, 'ALL', LOG_DEBUG);
}
return self::$levelMap[LoggerLevel::ALL];
}
/**
* Return the syslog equivalent of this level as an integer.
* @return integer
*/
public function getSyslogEquivalent() {
return $this->syslogEquivalent;
}
/**
* Returns <i>true</i> if this level has a higher or equal
* level than the level passed as argument, <i>false</i>
* otherwise.
*
* @param LoggerLevel $other
* @return boolean
*/
public function isGreaterOrEqual($other) {
return $this->level >= $other->level;
}
/**
* Returns the string representation of this level.
* @return string
*/
public function toString() {
return $this->levelStr;
}
/**
* Returns the string representation of this level.
* @return string
*/
public function __toString() {
return $this->toString();
}
/**
* Returns the integer representation of this level.
* @return integer
*/
public function toInt() {
return $this->level;
}
/**
* Convert the input argument to a level. If the conversion fails, then
* this method returns the provided default level.
*
* @param mixed $arg The value to convert to level.
* @param LoggerLevel $default Value to return if conversion is not possible.
* @return LoggerLevel
*/
public static function toLevel($arg, $defaultLevel = null) {
if(is_int($arg)) {
switch($arg) {
case self::ALL: return self::getLevelAll();
case self::TRACE: return self::getLevelTrace();
case self::DEBUG: return self::getLevelDebug();
case self::INFO: return self::getLevelInfo();
case self::WARN: return self::getLevelWarn();
case self::ERROR: return self::getLevelError();
case self::FATAL: return self::getLevelFatal();
case self::OFF: return self::getLevelOff();
default: return $defaultLevel;
}
} else {
switch(strtoupper($arg)) {
case 'ALL': return self::getLevelAll();
case 'TRACE': return self::getLevelTrace();
case 'DEBUG': return self::getLevelDebug();
case 'INFO': return self::getLevelInfo();
case 'WARN': return self::getLevelWarn();
case 'ERROR': return self::getLevelError();
case 'FATAL': return self::getLevelFatal();
case 'OFF': return self::getLevelOff();
default: return $defaultLevel;
}
}
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* @package log4php
*/
/**
* The internal representation of caller location information.
*
* @version $Revision: 1379738 $
* @package log4php
* @since 0.3
*/
class LoggerLocationInfo {
/** The value to return when the location information is not available. */
const LOCATION_INFO_NA = 'NA';
/**
* Caller line number.
* @var integer
*/
protected $lineNumber;
/**
* Caller file name.
* @var string
*/
protected $fileName;
/**
* Caller class name.
* @var string
*/
protected $className;
/**
* Caller method name.
* @var string
*/
protected $methodName;
/**
* All the information combined.
* @var string
*/
protected $fullInfo;
/**
* Instantiate location information based on a {@link PHP_MANUAL#debug_backtrace}.
*
* @param array $trace
* @param mixed $caller
*/
public function __construct($trace, $fqcn = null) {
$this->lineNumber = isset($trace['line']) ? $trace['line'] : null;
$this->fileName = isset($trace['file']) ? $trace['file'] : null;
$this->className = isset($trace['class']) ? $trace['class'] : null;
$this->methodName = isset($trace['function']) ? $trace['function'] : null;
$this->fullInfo = $this->getClassName() . '.' . $this->getMethodName() .
'(' . $this->getFileName() . ':' . $this->getLineNumber() . ')';
}
/** Returns the caller class name. */
public function getClassName() {
return ($this->className === null) ? self::LOCATION_INFO_NA : $this->className;
}
/** Returns the caller file name. */
public function getFileName() {
return ($this->fileName === null) ? self::LOCATION_INFO_NA : $this->fileName;
}
/** Returns the caller line number. */
public function getLineNumber() {
return ($this->lineNumber === null) ? self::LOCATION_INFO_NA : $this->lineNumber;
}
/** Returns the caller method name. */
public function getMethodName() {
return ($this->methodName === null) ? self::LOCATION_INFO_NA : $this->methodName;
}
/** Returns the full information of the caller. */
public function getFullInfo() {
return ($this->fullInfo === null) ? self::LOCATION_INFO_NA : $this->fullInfo;
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* @package log4php
*/
/**
* The LoggerMDC class provides _mapped diagnostic contexts_.
*
* A Mapped Diagnostic Context, or MDC in short, is an instrument for
* distinguishing interleaved log output from different sources. Log output
* is typically interleaved when a server handles multiple clients
* near-simultaneously.
*
* This class is similar to the {@link LoggerNDC} class except that
* it is based on a map instead of a stack.
*
* @version $Revision: 1343630 $
* @since 0.3
* @package log4php
*/
class LoggerMDC {
/** Holds the context map. */
private static $map = array();
/**
* Stores a context value as identified with the key parameter into the
* context map.
*
* @param string $key the key
* @param string $value the value
*/
public static function put($key, $value) {
self::$map[$key] = $value;
}
/**
* Returns the context value identified by the key parameter.
*
* @param string $key The key.
* @return string The context or an empty string if no context found
* for given key.
*/
public static function get($key) {
return isset(self::$map[$key]) ? self::$map[$key] : '';
}
/**
* Returns the contex map as an array.
* @return array The MDC context map.
*/
public static function getMap() {
return self::$map;
}
/**
* Removes the the context identified by the key parameter.
*
* Only affects user mappings, not $_ENV or $_SERVER.
*
* @param string $key The key to be removed.
*/
public static function remove($key) {
unset(self::$map[$key]);
}
/**
* Clears the mapped diagnostic context.
*/
public static function clear() {
self::$map = array();
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* @package log4php
*/
/**
* The NDC class implements <i>nested diagnostic contexts</i>.
*
* NDC was defined by Neil Harrison in the article "Patterns for Logging
* Diagnostic Messages" part of the book <i>"Pattern Languages of
* Program Design 3"</i> edited by Martin et al.
*
* A Nested Diagnostic Context, or NDC in short, is an instrument
* to distinguish interleaved log output from different sources. Log
* output is typically interleaved when a server handles multiple
* clients near-simultaneously.
*
* This class is similar to the {@link LoggerMDC} class except that it is
* based on a stack instead of a map.
*
* Interleaved log output can still be meaningful if each log entry
* from different contexts had a distinctive stamp. This is where NDCs
* come into play.
*
* <b>Note that NDCs are managed on a per thread basis</b>.
*
* NDC operations such as {@link push()}, {@link pop()},
* {@link clear()}, {@link getDepth()} and {@link setMaxDepth()}
* affect the NDC of the <i>current</i> thread only. NDCs of other
* threads remain unaffected.
*
* For example, a servlet can build a per client request NDC
* consisting the clients host name and other information contained in
* the the request. <i>Cookies</i> are another source of distinctive
* information. To build an NDC one uses the {@link push()}
* operation.
*
* Simply put,
*
* - Contexts can be nested.
* - When entering a context, call <kbd>LoggerNDC::push()</kbd>
* As a side effect, if there is no nested diagnostic context for the
* current thread, this method will create it.
* - When leaving a context, call <kbd>LoggerNDC::pop()</kbd>
* - <b>When exiting a thread make sure to call {@link remove()}</b>
*
* There is no penalty for forgetting to match each
* <kbd>push</kbd> operation with a corresponding <kbd>pop</kbd>,
* except the obvious mismatch between the real application context
* and the context set in the NDC.
*
* If configured to do so, {@link LoggerPatternLayout} and {@link LoggerLayoutTTCC}
* instances automatically retrieve the nested diagnostic
* context for the current thread without any user intervention.
* Hence, even if a servlet is serving multiple clients
* simultaneously, the logs emanating from the same code (belonging to
* the same category) can still be distinguished because each client
* request will have a different NDC tag.
*
* Example:
*
* {@example ../../examples/php/ndc.php 19}<br>
*
* With the properties file:
*
* {@example ../../examples/resources/ndc.properties 18}<br>
*
* Will result in the following (notice the conn and client ids):
*
* <pre>
* 2009-09-13 19:04:27 DEBUG root conn=1234: just received a new connection in src/examples/php/ndc.php at 23
* 2009-09-13 19:04:27 DEBUG root conn=1234 client=ab23: some more messages that can in src/examples/php/ndc.php at 25
* 2009-09-13 19:04:27 DEBUG root conn=1234 client=ab23: now related to a client in src/examples/php/ndc.php at 26
* 2009-09-13 19:04:27 DEBUG root : back and waiting for new connections in src/examples/php/ndc.php at 29
* </pre>
*
* @version $Revision: 1350602 $
* @package log4php
* @since 0.3
*/
class LoggerNDC {
/** This is the repository of NDC stack */
private static $stack = array();
/**
* Clear any nested diagnostic information if any. This method is
* useful in cases where the same thread can be potentially used
* over and over in different unrelated contexts.
*
* <p>This method is equivalent to calling the {@link setMaxDepth()}
* method with a zero <var>maxDepth</var> argument.
*/
public static function clear() {
self::$stack = array();
}
/**
* Never use this method directly, use the {@link LoggerLoggingEvent::getNDC()} method instead.
* @return array
*/
public static function get() {
return implode(' ', self::$stack);
}
/**
* Get the current nesting depth of this diagnostic context.
*
* @see setMaxDepth()
* @return integer
*/
public static function getDepth() {
return count(self::$stack);
}
/**
* Clients should call this method before leaving a diagnostic
* context.
*
* <p>The returned value is the value that was pushed last. If no
* context is available, then the empty string "" is returned.</p>
*
* @return string The innermost diagnostic context.
*/
public static function pop() {
if(count(self::$stack) > 0) {
return array_pop(self::$stack);
} else {
return '';
}
}
/**
* Looks at the last diagnostic context at the top of this NDC
* without removing it.
*
* <p>The returned value is the value that was pushed last. If no
* context is available, then the empty string "" is returned.</p>
* @return string The innermost diagnostic context.
*/
public static function peek() {
if(count(self::$stack) > 0) {
return end(self::$stack);
} else {
return '';
}
}
/**
* Push new diagnostic context information for the current thread.
*
* <p>The contents of the <var>message</var> parameter is
* determined solely by the client.
*
* @param string $message The new diagnostic context information.
*/
public static function push($message) {
array_push(self::$stack, (string)$message);
}
/**
* Remove the diagnostic context for this thread.
*/
public static function remove() {
LoggerNDC::clear();
}
/**
* Set maximum depth of this diagnostic context. If the current
* depth is smaller or equal to <var>maxDepth</var>, then no
* action is taken.
*
* <p>This method is a convenient alternative to multiple
* {@link pop()} calls. Moreover, it is often the case that at
* the end of complex call sequences, the depth of the NDC is
* unpredictable. The {@link setMaxDepth()} method circumvents
* this problem.
*
* @param integer $maxDepth
* @see getDepth()
*/
public static function setMaxDepth($maxDepth) {
$maxDepth = (int)$maxDepth;
if(LoggerNDC::getDepth() > $maxDepth) {
self::$stack = array_slice(self::$stack, 0, $maxDepth);
}
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* @package log4php
*/
/**
* Provides methods for reflective use on php objects
* @package log4php
*/
class LoggerReflectionUtils {
/** the target object */
private $obj;
/**
* Create a new LoggerReflectionUtils for the specified Object.
* This is done in prepartion for invoking {@link setProperty()}
* one or more times.
* @param object &$obj the object for which to set properties
*/
public function __construct($obj) {
$this->obj = $obj;
}
/**
* Set the properties of an object passed as a parameter in one
* go. The <code>properties</code> are parsed relative to a
* <code>prefix</code>.
*
* @param object $obj The object to configure.
* @param array $properties An array containing keys and values.
* @param string $prefix Only keys having the specified prefix will be set.
*/
// TODO: check, if this is really useful
public static function setPropertiesByObject($obj, $properties, $prefix) {
$pSetter = new LoggerReflectionUtils($obj);
return $pSetter->setProperties($properties, $prefix);
}
/**
* Set the properites for the object that match the
* <code>prefix</code> passed as parameter.
*
* Example:
*
* $arr['xxxname'] = 'Joe';
* $arr['xxxmale'] = true;
* and prefix xxx causes setName and setMale.
*
* @param array $properties An array containing keys and values.
* @param string $prefix Only keys having the specified prefix will be set.
*/
public function setProperties($properties, $prefix) {
$len = strlen($prefix);
reset($properties);
while(list($key,) = each($properties)) {
if(strpos($key, $prefix) === 0) {
if(strpos($key, '.', ($len + 1)) > 0) {
continue;
}
$value = $properties[$key];
$key = substr($key, $len);
if($key == 'layout' and ($this->obj instanceof LoggerAppender)) {
continue;
}
$this->setProperty($key, $value);
}
}
$this->activate();
}
/**
* Set a property on this PropertySetter's Object. If successful, this
* method will invoke a setter method on the underlying Object. The
* setter is the one for the specified property name and the value is
* determined partly from the setter argument type and partly from the
* value specified in the call to this method.
*
* <p>If the setter expects a String no conversion is necessary.
* If it expects an int, then an attempt is made to convert 'value'
* to an int using new Integer(value). If the setter expects a boolean,
* the conversion is by new Boolean(value).
*
* @param string $name name of the property
* @param string $value String value of the property
*/
public function setProperty($name, $value) {
if($value === null) {
return;
}
$method = "set" . ucfirst($name);
if(!method_exists($this->obj, $method)) {
throw new Exception("Error setting log4php property $name to $value: no method $method in class ".get_class($this->obj)."!");
} else {
return call_user_func(array($this->obj, $method), $value);
}
}
public function activate() {
if(method_exists($this->obj, 'activateoptions')) {
return call_user_func(array($this->obj, 'activateoptions'));
}
}
/**
* Creates an instances from the given class name.
*
* @param string $classname
* @return an object from the class with the given classname
*/
public static function createObject($class) {
if(!empty($class)) {
return new $class();
}
return null;
}
/**
* @param object $object
* @param string $name
* @param mixed $value
*/
public static function setter($object, $name, $value) {
if (empty($name)) {
return false;
}
$methodName = 'set'.ucfirst($name);
if (method_exists($object, $methodName)) {
return call_user_func(array($object, $methodName), $value);
} else {
return false;
}
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* @package log4php
*/
/**
* The root logger.
*
* @version $Revision: 1343190 $
* @package log4php
* @see Logger
*/
class LoggerRoot extends Logger {
/**
* Constructor
*
* @param integer $level initial log level
*/
public function __construct(LoggerLevel $level = null) {
parent::__construct('root');
if($level == null) {
$level = LoggerLevel::getLevelAll();
}
$this->setLevel($level);
}
/**
* @return LoggerLevel the level
*/
public function getEffectiveLevel() {
return $this->getLevel();
}
/**
* Override level setter to prevent setting the root logger's level to
* null. Root logger must always have a level.
*
* @param LoggerLevel $level
*/
public function setLevel(LoggerLevel $level = null) {
if (isset($level)) {
parent::setLevel($level);
} else {
trigger_error("log4php: Cannot set LoggerRoot level to null.", E_USER_WARNING);
}
}
/**
* Override parent setter. Root logger cannot have a parent.
* @param Logger $parent
*/
public function setParent(Logger $parent) {
trigger_error("log4php: LoggerRoot cannot have a parent.", E_USER_WARNING);
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* @package log4php
*/
/**
* The internal representation of throwables.
*
* @package log4php
* @since 2.1
*/
class LoggerThrowableInformation {
/** @var Exception Throwable to log */
private $throwable;
/** @var array Array of throwable messages */
private $throwableArray;
/**
* Create a new instance
*
* @param $throwable - a throwable as a exception
* @param $logger - Logger reference
*/
public function __construct(Exception $throwable) {
$this->throwable = $throwable;
}
/**
* Return source exception
*
* @return Exception
*/
public function getThrowable() {
return $this->throwable;
}
/**
* @desc Returns string representation of throwable
*
* @return array
*/
public function getStringRepresentation() {
if (!is_array($this->throwableArray)) {
$renderer = new LoggerRendererException();
$this->throwableArray = explode("\n", $renderer->render($this->throwable));
}
return $this->throwableArray;
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* LoggerAppenderConsole appends log events either to the standard output
* stream (php://stdout) or the standard error stream (php://stderr).
*
* **Note**: Use this Appender with command-line php scripts. On web scripts
* this appender has no effects.
*
* This appender uses a layout.
*
* ## Configurable parameters: ##
*
* - **target** - the target stream: "stdout" or "stderr"
*
* @version $Revision: 1343601 $
* @package log4php
* @subpackage appenders
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @link http://logging.apache.org/log4php/docs/appenders/console.html Appender documentation
*/
class LoggerAppenderConsole extends LoggerAppender {
/** The standard otuput stream. */
const STDOUT = 'php://stdout';
/** The standard error stream.*/
const STDERR = 'php://stderr';
/** The 'target' parameter. */
protected $target = self::STDOUT;
/**
* Stream resource for the target stream.
* @var resource
*/
protected $fp = null;
public function activateOptions() {
$this->fp = fopen($this->target, 'w');
if(is_resource($this->fp) && $this->layout !== null) {
fwrite($this->fp, $this->layout->getHeader());
}
$this->closed = (bool)is_resource($this->fp) === false;
}
public function close() {
if($this->closed != true) {
if (is_resource($this->fp) && $this->layout !== null) {
fwrite($this->fp, $this->layout->getFooter());
fclose($this->fp);
}
$this->closed = true;
}
}
public function append(LoggerLoggingEvent $event) {
if (is_resource($this->fp) && $this->layout !== null) {
fwrite($this->fp, $this->layout->format($event));
}
}
/**
* Sets the 'target' parameter.
* @param string $target
*/
public function setTarget($target) {
$value = trim($target);
if ($value == self::STDOUT || strtoupper($value) == 'STDOUT') {
$this->target = self::STDOUT;
} elseif ($value == self::STDERR || strtoupper($value) == 'STDERR') {
$this->target = self::STDERR;
} else {
$target = var_export($target);
$this->warn("Invalid value given for 'target' property: [$target]. Property not set.");
}
}
/**
* Returns the value of the 'target' parameter.
* @return string
*/
public function getTarget() {
return $this->target;
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* An Appender that automatically creates a new logfile each day.
*
* The file is rolled over once a day. That means, for each day a new file
* is created. A formatted version of the date pattern is used as to create
* the file name using the {@link PHP_MANUAL#sprintf} function.
*
* This appender uses a layout.
*
* ##Configurable parameters:##
*
* - **datePattern** - Format for the date in the file path, follows formatting
* rules used by the PHP date() function. Default value: "Ymd".
* - **file** - Path to the target file. Should contain a %s which gets
* substituted by the date.
* - **append** - If set to true, the appender will append to the file,
* otherwise the file contents will be overwritten. Defaults to true.
*
* @version $Revision: 1382274 $
* @package log4php
* @subpackage appenders
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @link http://logging.apache.org/log4php/docs/appenders/daily-file.html Appender documentation
*/
class LoggerAppenderDailyFile extends LoggerAppenderFile {
/**
* The 'datePattern' parameter.
* Determines how date will be formatted in file name.
* @var string
*/
protected $datePattern = "Ymd";
/**
* Current date which was used when opening a file.
* Used to determine if a rollover is needed when the date changes.
* @var string
*/
protected $currentDate;
/** Additional validation for the date pattern. */
public function activateOptions() {
parent::activateOptions();
if (empty($this->datePattern)) {
$this->warn("Required parameter 'datePattern' not set. Closing appender.");
$this->closed = true;
return;
}
}
/**
* Appends a logging event.
*
* If the target file changes because of passage of time (e.g. at midnight)
* the current file is closed. A new file, with the new date, will be
* opened by the write() method.
*/
public function append(LoggerLoggingEvent $event) {
$eventDate = $this->getDate($event->getTimestamp());
// Initial setting of current date
if (!isset($this->currentDate)) {
$this->currentDate = $eventDate;
}
// Check if rollover is needed
else if ($this->currentDate !== $eventDate) {
$this->currentDate = $eventDate;
// Close the file if it's open.
// Note: $this->close() is not called here because it would set
// $this->closed to true and the appender would not recieve
// any more logging requests
if (is_resource($this->fp)) {
$this->write($this->layout->getFooter());
fclose($this->fp);
}
$this->fp = null;
}
parent::append($event);
}
/** Renders the date using the configured <var>datePattern<var>. */
protected function getDate($timestamp = null) {
return date($this->datePattern, $timestamp);
}
/**
* Determines target file. Replaces %s in file path with a date.
*/
protected function getTargetFile() {
return str_replace('%s', $this->currentDate, $this->file);
}
/**
* Sets the 'datePattern' parameter.
* @param string $datePattern
*/
public function setDatePattern($datePattern) {
$this->setString('datePattern', $datePattern);
}
/**
* Returns the 'datePattern' parameter.
* @return string
*/
public function getDatePattern() {
return $this->datePattern;
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* LoggerAppenderEcho uses the PHP echo() function to output events.
*
* This appender uses a layout.
*
* ## Configurable parameters: ##
*
* - **htmlLineBreaks** - If set to true, a <br /> element will be inserted
* before each line break in the logged message. Default is false.
*
* @version $Revision: 1337820 $
* @package log4php
* @subpackage appenders
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @link http://logging.apache.org/log4php/docs/appenders/echo.html Appender documentation
*/
class LoggerAppenderEcho extends LoggerAppender {
/**
* Used to mark first append. Set to false after first append.
* @var boolean
*/
protected $firstAppend = true;
/**
* If set to true, a <br /> element will be inserted before each line
* break in the logged message. Default value is false. @var boolean
*/
protected $htmlLineBreaks = false;
public function close() {
if($this->closed != true) {
if(!$this->firstAppend) {
echo $this->layout->getFooter();
}
}
$this->closed = true;
}
public function append(LoggerLoggingEvent $event) {
if($this->layout !== null) {
if($this->firstAppend) {
echo $this->layout->getHeader();
$this->firstAppend = false;
}
$text = $this->layout->format($event);
if ($this->htmlLineBreaks) {
$text = nl2br($text);
}
echo $text;
}
}
/**
* Sets the 'htmlLineBreaks' parameter.
* @param boolean $value
*/
public function setHtmlLineBreaks($value) {
$this->setBoolean('htmlLineBreaks', $value);
}
/**
* Returns the 'htmlLineBreaks' parameter.
* @returns boolean
*/
public function getHtmlLineBreaks() {
return $this->htmlLineBreaks;
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* LoggerAppenderFile appends log events to a file.
*
* This appender uses a layout.
*
* ## Configurable parameters: ##
*
* - **file** - Path to the target file. Relative paths are resolved based on
* the working directory.
* - **append** - If set to true, the appender will append to the file,
* otherwise the file contents will be overwritten.
*
* @version $Revision: 1382274 $
* @package log4php
* @subpackage appenders
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @link http://logging.apache.org/log4php/docs/appenders/file.html Appender documentation
*/
class LoggerAppenderFile extends LoggerAppender {
/**
* If set to true, the file is locked before appending. This allows
* concurrent access. However, appending without locking is faster so
* it should be used where appropriate.
*
* TODO: make this a configurable parameter
*
* @var boolean
*/
protected $locking = true;
/**
* If set to true, appends to file. Otherwise overwrites it.
* @var boolean
*/
protected $append = true;
/**
* Path to the target file.
* @var string
*/
protected $file;
/**
* The file resource.
* @var resource
*/
protected $fp;
/**
* Helper function which can be easily overriden by daily file appender.
*/
protected function getTargetFile() {
return $this->file;
}
/**
* Acquires the target file resource, creates the destination folder if
* necessary. Writes layout header to file.
*
* @return boolean FALSE if opening failed
*/
protected function openFile() {
$file = $this->getTargetFile();
// Create the target folder if needed
if(!is_file($file)) {
$dir = dirname($file);
if(!is_dir($dir)) {
$success = mkdir($dir, 0777, true);
if ($success === false) {
$this->warn("Failed creating target directory [$dir]. Closing appender.");
$this->closed = true;
return false;
}
}
}
$mode = $this->append ? 'a' : 'w';
$this->fp = fopen($file, $mode);
if ($this->fp === false) {
$this->warn("Failed opening target file. Closing appender.");
$this->fp = null;
$this->closed = true;
return false;
}
// Required when appending with concurrent access
if($this->append) {
fseek($this->fp, 0, SEEK_END);
}
// Write the header
$this->write($this->layout->getHeader());
}
/**
* Writes a string to the target file. Opens file if not already open.
* @param string $string Data to write.
*/
protected function write($string) {
// Lazy file open
if(!isset($this->fp)) {
if ($this->openFile() === false) {
return; // Do not write if file open failed.
}
}
if ($this->locking) {
$this->writeWithLocking($string);
} else {
$this->writeWithoutLocking($string);
}
}
protected function writeWithLocking($string) {
if(flock($this->fp, LOCK_EX)) {
if(fwrite($this->fp, $string) === false) {
$this->warn("Failed writing to file. Closing appender.");
$this->closed = true;
}
flock($this->fp, LOCK_UN);
} else {
$this->warn("Failed locking file for writing. Closing appender.");
$this->closed = true;
}
}
protected function writeWithoutLocking($string) {
if(fwrite($this->fp, $string) === false) {
$this->warn("Failed writing to file. Closing appender.");
$this->closed = true;
}
}
public function activateOptions() {
if (empty($this->file)) {
$this->warn("Required parameter 'file' not set. Closing appender.");
$this->closed = true;
return;
}
}
public function close() {
if (is_resource($this->fp)) {
$this->write($this->layout->getFooter());
fclose($this->fp);
}
$this->fp = null;
$this->closed = true;
}
public function append(LoggerLoggingEvent $event) {
$this->write($this->layout->format($event));
}
/**
* Sets the 'file' parameter.
* @param string $file
*/
public function setFile($file) {
$this->setString('file', $file);
}
/**
* Returns the 'file' parameter.
* @return string
*/
public function getFile() {
return $this->file;
}
/**
* Returns the 'append' parameter.
* @return boolean
*/
public function getAppend() {
return $this->append;
}
/**
* Sets the 'append' parameter.
* @param boolean $append
*/
public function setAppend($append) {
$this->setBoolean('append', $append);
}
/**
* Sets the 'file' parmeter. Left for legacy reasons.
* @param string $fileName
* @deprecated Use setFile() instead.
*/
public function setFileName($fileName) {
$this->setFile($fileName);
}
/**
* Returns the 'file' parmeter. Left for legacy reasons.
* @return string
* @deprecated Use getFile() instead.
*/
public function getFileName() {
return $this->getFile();
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* Logs messages as HTTP headers using the FirePHP Insight API.
*
* This appender requires the FirePHP server library version 1.0 or later.
*
* ## Configurable parameters: ##
*
* - **target** - (string) The target to which messages will be sent. Possible options are
* 'page' (default), 'request', 'package' and 'controller'. For more details,
* see FirePHP documentation.
*
* This class was originally contributed by Bruce Ingalls (Bruce.Ingalls-at-gmail-dot-com).
*
* @link https://github.com/firephp/firephp FirePHP homepage.
* @link http://sourcemint.com/github.com/firephp/firephp/1:1.0.0b1rc6/-docs/Welcome FirePHP documentation.
* @link http://sourcemint.com/github.com/firephp/firephp/1:1.0.0b1rc6/-docs/Configuration/Constants FirePHP constants documentation.
* @link http://logging.apache.org/log4php/docs/appenders/firephp.html Appender documentation
*
* @version $Revision: 1343684 $
* @package log4php
* @subpackage appenders
* @since 2.3
*/
class LoggerAppenderFirePHP extends LoggerAppender {
/**
* Instance of the Insight console class.
* @var Insight_Plugin_Console
*/
protected $console;
/**
* The target for log messages. Possible values are: 'page' (default),
* 'request', 'package' and 'contoller'.
*/
protected $target = 'page';
public function activateOptions() {
if (method_exists('FirePHP', 'to')) {
$this->console = FirePHP::to($this->target)->console();
$this->closed = false;
} else {
$this->warn('FirePHP is not installed correctly. Closing appender.');
}
}
public function append(LoggerLoggingEvent $event) {
$msg = $event->getMessage();
// Skip formatting for objects and arrays which are handled by FirePHP.
if (!is_array($msg) && !is_object($msg)) {
$msg = $this->getLayout()->format($event);
}
switch ($event->getLevel()->toInt()) {
case LoggerLevel::TRACE:
case LoggerLevel::DEBUG:
$this->console->log($msg);
break;
case LoggerLevel::INFO:
$this->console->info($msg);
break;
case LoggerLevel::WARN:
$this->console->warn($msg);
break;
case LoggerLevel::ERROR:
case LoggerLevel::FATAL:
$this->console->error($msg);
break;
}
}
/** Returns the target. */
public function getTarget() {
return $this->target;
}
/** Sets the target. */
public function setTarget($target) {
$this->setString('target', $target);
}
}
\ No newline at end of file
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* LoggerAppenderMail appends log events via email.
*
* This appender does not send individual emails for each logging requests but
* will collect them in a buffer and send them all in a single email once the
* appender is closed (i.e. when the script exists). Because of this, it may
* not appropriate for long running scripts, in which case
* LoggerAppenderMailEvent might be a better choice.
*
* This appender uses a layout.
*
* ## Configurable parameters: ##
*
* - **to** - Email address(es) to which the log will be sent. Multiple email
* addresses may be specified by separating them with a comma.
* - **from** - Email address which will be used in the From field.
* - **subject** - Subject of the email message.
*
* @version $Revision: 1337820 $
* @package log4php
* @subpackage appenders
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @link http://logging.apache.org/log4php/docs/appenders/mail.html Appender documentation
*/
class LoggerAppenderMail extends LoggerAppender {
/**
* Email address to put in From field of the email.
* @var string
*/
protected $from = null;
/**
* The subject of the email.
* @var string
*/
protected $subject = 'Log4php Report';
/**
* One or more comma separated email addresses to which to send the email.
* @var string
*/
protected $to = null;
/**
* Indiciates whether this appender should run in dry mode.
* @deprecated
* @var boolean
*/
protected $dry = false;
/**
* Buffer which holds the email contents before it is sent.
* @var string
*/
protected $body = '';
public function append(LoggerLoggingEvent $event) {
if($this->layout !== null) {
$this->body .= $this->layout->format($event);
}
}
public function close() {
if($this->closed != true) {
$from = $this->from;
$to = $this->to;
if(!empty($this->body) and $from !== null and $to !== null and $this->layout !== null) {
$subject = $this->subject;
if(!$this->dry) {
mail(
$to, $subject,
$this->layout->getHeader() . $this->body . $this->layout->getFooter(),
"From: {$from}\r\n");
} else {
echo "DRY MODE OF MAIL APP.: Send mail to: ".$to." with content: ".$this->body;
}
}
$this->closed = true;
}
}
/** Sets the 'subject' parameter. */
public function setSubject($subject) {
$this->setString('subject', $subject);
}
/** Returns the 'subject' parameter. */
public function getSubject() {
return $this->subject;
}
/** Sets the 'to' parameter. */
public function setTo($to) {
$this->setString('to', $to);
}
/** Returns the 'to' parameter. */
public function getTo() {
return $this->to;
}
/** Sets the 'from' parameter. */
public function setFrom($from) {
$this->setString('from', $from);
}
/** Returns the 'from' parameter. */
public function getFrom() {
return $this->from;
}
/** Enables or disables dry mode. */
public function setDry($dry) {
$this->setBoolean('dry', $dry);
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* LoggerAppenderMailEvent appends individual log events via email.
*
* This appender is similar to LoggerAppenderMail, except that it sends each
* each log event in an individual email message at the time when it occurs.
*
* This appender uses a layout.
*
* ## Configurable parameters: ##
*
* - **to** - Email address(es) to which the log will be sent. Multiple email
* addresses may be specified by separating them with a comma.
* - **from** - Email address which will be used in the From field.
* - **subject** - Subject of the email message.
* - **smtpHost** - Used to override the SMTP server. Only works on Windows.
* - **port** - Used to override the default SMTP server port. Only works on
* Windows.
*
* @version $Revision: 1343601 $
* @package log4php
* @subpackage appenders
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @link http://logging.apache.org/log4php/docs/appenders/mail-event.html Appender documentation
*/
class LoggerAppenderMailEvent extends LoggerAppender {
/**
* Email address to put in From field of the email.
* @var string
*/
protected $from;
/**
* Mail server port (widnows only).
* @var integer
*/
protected $port = 25;
/**
* Mail server hostname (windows only).
* @var string
*/
protected $smtpHost;
/**
* The subject of the email.
* @var string
*/
protected $subject = 'Log4php Report';
/**
* One or more comma separated email addresses to which to send the email.
* @var string
*/
protected $to = null;
/**
* Indiciates whether this appender should run in dry mode.
* @deprecated
* @var boolean
*/
protected $dry = false;
public function activateOptions() {
if (empty($this->to)) {
$this->warn("Required parameter 'to' not set. Closing appender.");
$this->close = true;
return;
}
$sendmail_from = ini_get('sendmail_from');
if (empty($this->from) and empty($sendmail_from)) {
$this->warn("Required parameter 'from' not set. Closing appender.");
$this->close = true;
return;
}
$this->closed = false;
}
public function append(LoggerLoggingEvent $event) {
$smtpHost = $this->smtpHost;
$prevSmtpHost = ini_get('SMTP');
if(!empty($smtpHost)) {
ini_set('SMTP', $smtpHost);
}
$smtpPort = $this->port;
$prevSmtpPort= ini_get('smtp_port');
if($smtpPort > 0 and $smtpPort < 65535) {
ini_set('smtp_port', $smtpPort);
}
// On unix only sendmail_path, which is PHP_INI_SYSTEM i.e. not changeable here, is used.
$addHeader = empty($this->from) ? '' : "From: {$this->from}\r\n";
if(!$this->dry) {
$result = mail($this->to, $this->subject, $this->layout->getHeader() . $this->layout->format($event) . $this->layout->getFooter($event), $addHeader);
} else {
echo "DRY MODE OF MAIL APP.: Send mail to: ".$this->to." with additional headers '".trim($addHeader)."' and content: ".$this->layout->format($event);
}
ini_set('SMTP', $prevSmtpHost);
ini_set('smtp_port', $prevSmtpPort);
}
/** Sets the 'from' parameter. */
public function setFrom($from) {
$this->setString('from', $from);
}
/** Returns the 'from' parameter. */
public function getFrom() {
return $this->from;
}
/** Sets the 'port' parameter. */
public function setPort($port) {
$this->setPositiveInteger('port', $port);
}
/** Returns the 'port' parameter. */
public function getPort() {
return $this->port;
}
/** Sets the 'smtpHost' parameter. */
public function setSmtpHost($smtpHost) {
$this->setString('smtpHost', $smtpHost);
}
/** Returns the 'smtpHost' parameter. */
public function getSmtpHost() {
return $this->smtpHost;
}
/** Sets the 'subject' parameter. */
public function setSubject($subject) {
$this->setString('subject', $subject);
}
/** Returns the 'subject' parameter. */
public function getSubject() {
return $this->subject;
}
/** Sets the 'to' parameter. */
public function setTo($to) {
$this->setString('to', $to);
}
/** Returns the 'to' parameter. */
public function getTo() {
return $this->to;
}
/** Enables or disables dry mode. */
public function setDry($dry) {
$this->setBoolean('dry', $dry);
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* A NullAppender merely exists, it never outputs a message to any device.
*
* This appender has no configurable parameters.
*
* @version $Revision: 1343601 $
* @package log4php
* @subpackage appenders
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @link http://logging.apache.org/log4php/docs/appenders/null.html Appender documentation
*/
class LoggerAppenderNull extends LoggerAppender {
/**
* This appender does not require a layout.
*/
protected $requiresLayout = false;
/**
* Do nothing.
*
* @param LoggerLoggingEvent $event
*/
public function append(LoggerLoggingEvent $event) {
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* LoggerAppenderPDO appender logs to a database using the PHP's PDO extension.
*
* ## Configurable parameters: ##
*
* - dsn - The Data Source Name (DSN) used to connect to the database.
* - user - Username used to connect to the database.
* - password - Password used to connect to the database.
* - table - Name of the table to which log entries are be inserted.
* - insertSQL - Sets the insert statement for a logging event. Defaults
* to the correct one - change only if you are sure what you are doing.
* - insertPattern - The conversion pattern to use in conjuction with insert
* SQL. Must contain the same number of comma separated
* conversion patterns as there are question marks in the
* insertSQL.
*
* @version $Revision: 1374546 $
* @package log4php
* @subpackage appenders
* @since 2.0
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @link http://logging.apache.org/log4php/docs/appenders/pdo.html Appender documentation
*/
class LoggerAppenderPDO extends LoggerAppender {
// ******************************************
// *** Configurable parameters ***
// ******************************************
/**
* DSN string used to connect to the database.
* @see http://www.php.net/manual/en/pdo.construct.php
*/
protected $dsn;
/** Database user name. */
protected $user;
/** Database password. */
protected $password;
/**
* The insert query.
*
* The __TABLE__ placeholder will be replaced by the table name from
* {@link $table}.
*
* The questionmarks are part of the prepared statement, and they must
* match the number of conversion specifiers in {@link insertPattern}.
*/
protected $insertSQL = "INSERT INTO __TABLE__ (timestamp, logger, level, message, thread, file, line) VALUES (?, ?, ?, ?, ?, ?, ?)";
/**
* A comma separated list of {@link LoggerPatternLayout} format strings
* which replace the "?" in {@link $insertSQL}.
*
* Must contain the same number of comma separated conversion patterns as
* there are question marks in {@link insertSQL}.
*
* @see LoggerPatternLayout For conversion patterns.
*/
protected $insertPattern = "%date{Y-m-d H:i:s},%logger,%level,%message,%pid,%file,%line";
/** Name of the table to which to append log events. */
protected $table = 'log4php_log';
/** The number of recconect attempts to make on failed append. */
protected $reconnectAttempts = 3;
// ******************************************
// *** Private memebers ***
// ******************************************
/**
* The PDO instance.
* @var PDO
*/
protected $db;
/**
* Prepared statement for the insert query.
* @var PDOStatement
*/
protected $preparedInsert;
/** This appender does not require a layout. */
protected $requiresLayout = false;
// ******************************************
// *** Appender methods ***
// ******************************************
/**
* Acquires a database connection based on parameters.
* Parses the insert pattern to create a chain of converters which will be
* used in forming query parameters from logging events.
*/
public function activateOptions() {
try {
$this->establishConnection();
} catch (PDOException $e) {
$this->warn("Failed connecting to database. Closing appender. Error: " . $e->getMessage());
$this->close();
return;
}
// Parse the insert patterns; pattern parts are comma delimited
$pieces = explode(',', $this->insertPattern);
$converterMap = LoggerLayoutPattern::getDefaultConverterMap();
foreach($pieces as $pattern) {
$parser = new LoggerPatternParser($pattern, $converterMap);
$this->converters[] = $parser->parse();
}
$this->closed = false;
}
/**
* Connects to the database, and prepares the insert query.
* @throws PDOException If connect or prepare fails.
*/
protected function establishConnection() {
// Acquire database connection
$this->db = new PDO($this->dsn, $this->user, $this->password);
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Prepare the insert statement
$insertSQL = str_replace('__TABLE__', $this->table, $this->insertSQL);
$this->preparedInsert = $this->db->prepare($insertSQL);
}
/**
* Appends a new event to the database.
*
* If writing to database fails, it will retry by re-establishing the
* connection up to $reconnectAttempts times. If writing still fails,
* the appender will close.
*/
public function append(LoggerLoggingEvent $event) {
for ($attempt = 1; $attempt <= $this->reconnectAttempts + 1; $attempt++) {
try {
// Attempt to write to database
$this->preparedInsert->execute($this->format($event));
$this->preparedInsert->closeCursor();
break;
} catch (PDOException $e) {
$this->warn("Failed writing to database: ". $e->getMessage());
// Close the appender if it's the last attempt
if ($attempt > $this->reconnectAttempts) {
$this->warn("Failed writing to database after {$this->reconnectAttempts} reconnect attempts. Closing appender.");
$this->close();
// Otherwise reconnect and try to write again
} else {
$this->warn("Attempting a reconnect (attempt $attempt of {$this->reconnectAttempts}).");
$this->establishConnection();
}
}
}
}
/**
* Converts the logging event to a series of database parameters by using
* the converter chain which was set up on activation.
*/
protected function format(LoggerLoggingEvent $event) {
$params = array();
foreach($this->converters as $converter) {
$buffer = '';
while ($converter !== null) {
$converter->format($buffer, $event);
$converter = $converter->next;
}
$params[] = $buffer;
}
return $params;
}
/**
* Closes the connection to the logging database
*/
public function close() {
// Close the connection (if any)
$this->db = null;
// Close the appender
$this->closed = true;
}
// ******************************************
// *** Accessor methods ***
// ******************************************
/**
* Returns the active database handle or null if not established.
* @return PDO
*/
public function getDatabaseHandle() {
return $this->db;
}
/** Sets the username. */
public function setUser($user) {
$this->setString('user', $user);
}
/** Returns the username. */
public function getUser($user) {
return $this->user;
}
/** Sets the password. */
public function setPassword($password) {
$this->setString('password', $password);
}
/** Returns the password. */
public function getPassword($password) {
return $this->password;
}
/** Sets the insert SQL. */
public function setInsertSQL($sql) {
$this->setString('insertSQL', $sql);
}
/** Returns the insert SQL. */
public function getInsertSQL($sql) {
return $this->insertSQL;
}
/** Sets the insert pattern. */
public function setInsertPattern($pattern) {
$this->setString('insertPattern', $pattern);
}
/** Returns the insert pattern. */
public function getInsertPattern($pattern) {
return $this->insertPattern;
}
/** Sets the table name. */
public function setTable($table) {
$this->setString('table', $table);
}
/** Returns the table name. */
public function getTable($table) {
return $this->table;
}
/** Sets the DSN string. */
public function setDSN($dsn) {
$this->setString('dsn', $dsn);
}
/** Returns the DSN string. */
public function getDSN($dsn) {
return $this->setString('dsn', $dsn);
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* LoggerAppenderPhp logs events by creating a PHP user-level message using
* the PHP's trigger_error()function.
*
* This appender has no configurable parameters.
*
* Levels are mapped as follows:
*
* - <b>level < WARN</b> mapped to E_USER_NOTICE
* - <b>WARN <= level < ERROR</b> mapped to E_USER_WARNING
* - <b>level >= ERROR</b> mapped to E_USER_ERROR
*
* @version $Revision: 1337820 $
* @package log4php
* @subpackage appenders
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @link http://logging.apache.org/log4php/docs/appenders/php.html Appender documentation
*/
class LoggerAppenderPhp extends LoggerAppender {
public function append(LoggerLoggingEvent $event) {
$level = $event->getLevel();
if($level->isGreaterOrEqual(LoggerLevel::getLevelError())) {
trigger_error($this->layout->format($event), E_USER_ERROR);
} else if ($level->isGreaterOrEqual(LoggerLevel::getLevelWarn())) {
trigger_error($this->layout->format($event), E_USER_WARNING);
} else {
trigger_error($this->layout->format($event), E_USER_NOTICE);
}
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* @package log4php
*/
/**
* LoggerAppenderRollingFile writes logging events to a specified file. The
* file is rolled over after a specified size has been reached.
*
* This appender uses a layout.
*
* ## Configurable parameters: ##
*
* - **file** - Path to the target file.
* - **append** - If set to true, the appender will append to the file,
* otherwise the file contents will be overwritten.
* - **maxBackupIndex** - Maximum number of backup files to keep. Default is 1.
* - **maxFileSize** - Maximum allowed file size (in bytes) before rolling
* over. Suffixes "KB", "MB" and "GB" are allowed. 10KB = 10240 bytes, etc.
* Default is 10M.
* - **compress** - If set to true, rolled-over files will be compressed.
* Requires the zlib extension.
*
* @version $Revision: 1394975 $
* @package log4php
* @subpackage appenders
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @link http://logging.apache.org/log4php/docs/appenders/rolling-file.html Appender documentation
*/
class LoggerAppenderRollingFile extends LoggerAppenderFile {
/** Compressing backup files is done in chunks, this determines how large. */
const COMPRESS_CHUNK_SIZE = 102400; // 100KB
/**
* The maximum size (in bytes) that the output file is allowed to reach
* before being rolled over to backup files.
*
* The default maximum file size is 10MB (10485760 bytes). Maximum value
* for this option may depend on the file system.
*
* @var integer
*/
protected $maxFileSize = 10485760;
/**
* Set the maximum number of backup files to keep around.
*
* Determines how many backup files are kept before the oldest is erased.
* This option takes a positive integer value. If set to zero, then there
* will be no backup files and the log file will be truncated when it
* reaches <var>maxFileSize</var>.
*
* There is one backup file by default.
*
* @var integer
*/
protected $maxBackupIndex = 1;
/**
* The <var>compress</var> parameter determindes the compression with zlib.
* If set to true, the rollover files are compressed and saved with the .gz extension.
* @var boolean
*/
protected $compress = false;
/**
* Set to true in the constructor if PHP >= 5.3.0. In that case clearstatcache
* supports conditional clearing of statistics.
* @var boolean
* @see http://php.net/manual/en/function.clearstatcache.php
*/
private $clearConditional = false;
/**
* Get the maximum size that the output file is allowed to reach
* before being rolled over to backup files.
* @return integer
*/
public function getMaximumFileSize() {
return $this->maxFileSize;
}
public function __construct($name = '') {
parent::__construct($name);
if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
$this->clearConditional = true;
}
}
/**
* Implements the usual roll over behaviour.
*
* If MaxBackupIndex is positive, then files File.1, ..., File.MaxBackupIndex -1 are renamed to File.2, ..., File.MaxBackupIndex.
* Moreover, File is renamed File.1 and closed. A new File is created to receive further log output.
*
* If MaxBackupIndex is equal to zero, then the File is truncated with no backup files created.
*
* Rollover must be called while the file is locked so that it is safe for concurrent access.
*
* @throws LoggerException If any part of the rollover procedure fails.
*/
private function rollOver() {
// If maxBackups <= 0, then there is no file renaming to be done.
if($this->maxBackupIndex > 0) {
// Delete the oldest file, to keep Windows happy.
$file = $this->file . '.' . $this->maxBackupIndex;
if (file_exists($file) && !unlink($file)) {
throw new LoggerException("Unable to delete oldest backup file from [$file].");
}
// Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2}
$this->renameArchievedLogs($this->file);
// Backup the active file
$this->moveToBackup($this->file);
}
// Truncate the active file
ftruncate($this->fp, 0);
rewind($this->fp);
}
private function moveToBackup($source) {
if ($this->compress) {
$target = $source . '.1.gz';
$this->compressFile($source, $target);
} else {
$target = $source . '.1';
copy($source, $target);
}
}
private function compressFile($source, $target) {
$target = 'compress.zlib://' . $target;
$fin = fopen($source, 'rb');
if ($fin === false) {
throw new LoggerException("Unable to open file for reading: [$source].");
}
$fout = fopen($target, 'wb');
if ($fout === false) {
throw new LoggerException("Unable to open file for writing: [$target].");
}
while (!feof($fin)) {
$chunk = fread($fin, self::COMPRESS_CHUNK_SIZE);
if (false === fwrite($fout, $chunk)) {
throw new LoggerException("Failed writing to compressed file.");
}
}
fclose($fin);
fclose($fout);
}
private function renameArchievedLogs($fileName) {
for($i = $this->maxBackupIndex - 1; $i >= 1; $i--) {
$source = $fileName . "." . $i;
if ($this->compress) {
$source .= '.gz';
}
if(file_exists($source)) {
$target = $fileName . '.' . ($i + 1);
if ($this->compress) {
$target .= '.gz';
}
rename($source, $target);
}
}
}
/**
* Writes a string to the target file. Opens file if not already open.
* @param string $string Data to write.
*/
protected function write($string) {
// Lazy file open
if(!isset($this->fp)) {
if ($this->openFile() === false) {
return; // Do not write if file open failed.
}
}
// Lock the file while writing and possible rolling over
if(flock($this->fp, LOCK_EX)) {
// Write to locked file
if(fwrite($this->fp, $string) === false) {
$this->warn("Failed writing to file. Closing appender.");
$this->closed = true;
}
// Stats cache must be cleared, otherwise filesize() returns cached results
// If supported (PHP 5.3+), clear only the state cache for the target file
if ($this->clearConditional) {
clearstatcache(true, $this->file);
} else {
clearstatcache();
}
// Rollover if needed
if (filesize($this->file) > $this->maxFileSize) {
try {
$this->rollOver();
} catch (LoggerException $ex) {
$this->warn("Rollover failed: " . $ex->getMessage() . " Closing appender.");
$this->closed = true;
}
}
flock($this->fp, LOCK_UN);
} else {
$this->warn("Failed locking file for writing. Closing appender.");
$this->closed = true;
}
}
public function activateOptions() {
parent::activateOptions();
if ($this->compress && !extension_loaded('zlib')) {
$this->warn("The 'zlib' extension is required for file compression. Disabling compression.");
$this->compression = false;
}
}
/**
* Set the 'maxBackupIndex' parameter.
* @param integer $maxBackupIndex
*/
public function setMaxBackupIndex($maxBackupIndex) {
$this->setPositiveInteger('maxBackupIndex', $maxBackupIndex);
}
/**
* Returns the 'maxBackupIndex' parameter.
* @return integer
*/
public function getMaxBackupIndex() {
return $this->maxBackupIndex;
}
/**
* Set the 'maxFileSize' parameter.
* @param mixed $maxFileSize
*/
public function setMaxFileSize($maxFileSize) {
$this->setFileSize('maxFileSize', $maxFileSize);
}
/**
* Returns the 'maxFileSize' parameter.
* @return integer
*/
public function getMaxFileSize() {
return $this->maxFileSize;
}
/**
* Set the 'maxFileSize' parameter (kept for backward compatibility).
* @param mixed $maxFileSize
* @deprecated Use setMaxFileSize() instead.
*/
public function setMaximumFileSize($maxFileSize) {
$this->warn("The 'maximumFileSize' parameter is deprecated. Use 'maxFileSize' instead.");
return $this->setMaxFileSize($maxFileSize);
}
/**
* Sets the 'compress' parameter.
* @param boolean $compress
*/
public function setCompress($compress) {
$this->setBoolean('compress', $compress);
}
/**
* Returns the 'compress' parameter.
* @param boolean
*/
public function getCompress() {
return $this->compress;
}
}
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* LoggerAppenderSocket appends to a network socket.
*
* ## Configurable parameters: ##
*
* - **remoteHost** - Target remote host.
* - **port** - Target port (optional, defaults to 4446).
* - **timeout** - Connection timeout in seconds (optional, defaults to
* 'default_socket_timeout' from php.ini)
*
* The socket will by default be opened in blocking mode.
*
* @version $Revision: 1337820 $
* @package log4php
* @subpackage appenders
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @link http://logging.apache.org/log4php/docs/appenders/socket.html Appender documentation
*/
class LoggerAppenderSocket extends LoggerAppender {
/**
* Target host.
* @see http://php.net/manual/en/function.fsockopen.php
*/
protected $remoteHost;
/** Target port */
protected $port = 4446;
/** Connection timeout in ms. */
protected $timeout;
// ******************************************
// *** Appender methods ***
// ******************************************
/** Override the default layout to use serialized. */
public function getDefaultLayout() {
return new LoggerLayoutSerialized();
}
public function activateOptions() {
if (empty($this->remoteHost)) {
$this->warn("Required parameter [remoteHost] not set. Closing appender.");
$this->closed = true;
return;
}
if (empty($this->timeout)) {
$this->timeout = ini_get("default_socket_timeout");
}
$this->closed = false;
}
public function append(LoggerLoggingEvent $event) {
$socket = fsockopen($this->remoteHost, $this->port, $errno, $errstr, $this->timeout);
if ($socket === false) {
$this->warn("Could not open socket to {$this->remoteHost}:{$this->port}. Closing appender.");
$this->closed = true;
return;
}
if (false === fwrite($socket, $this->layout->format($event))) {
$this->warn("Error writing to socket. Closing appender.");
$this->closed = true;
}
fclose($socket);
}
// ******************************************
// *** Accessor methods ***
// ******************************************
/** Sets the target host. */
public function setRemoteHost($hostname) {
$this->setString('remoteHost', $hostname);
}
/** Sets the target port */
public function setPort($port) {
$this->setPositiveInteger('port', $port);
}
/** Sets the timeout. */
public function setTimeout($timeout) {
$this->setPositiveInteger('timeout', $timeout);
}
/** Returns the target host. */
public function getRemoteHost() {
return $this->getRemoteHost();
}
/** Returns the target port. */
public function getPort() {
return $this->port;
}
/** Returns the timeout */
public function getTimeout() {
return $this->timeout;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment