Golang写了一个帮助调试的代理程序,PHP实现了一个类用于输出调试信息
<?php /** * PD * ProxyDebug * * @author kun* @copyright 2014 kun * @license http://www.php.net/license/3_01.txt PHP License 3.01 * @version 1.0 * @link https://github.com/yangxikun/tag-parse * @since 1.0 */ /** * PD * * @author rokety* @license http://www.php.net/license/3_01.txt PHP License 3.01 * @version 1.0 * @link * @since 1.0 */ class PD { protected static $debugItemCount = 0; protected static $debugGroupCount = 0; protected static $group = array(); protected static $start; protected static $offset = 0; protected static $varNameString = null; /** * getVarName * get the variable name * * @access protected * @static * * @return string */ protected static function getVarName() { if (self::$varNameString === null) { $trace = debug_backtrace(); $line = file($trace[3]['file']); self::$varNameString = $line[$trace[3]['line']-1]; } preg_match( '~\$([\w\d_]+)~', self::$varNameString, $matches, PREG_OFFSET_CAPTURE, self::$offset ); if (!isset($matches[1])) { throw new Exception('Error Params, should use $variable as params', 1); } self::$offset = $matches[1][1]; return $matches[1][0]; } /** * func * * @param string $type debug type(info, warn, error) * @param mixed $arg debug variable * * @access protected * @static * * @return null */ protected static function func($type, $arg) { if (self::$start) { self::$group[] = array( "category"=>$type, "type"=>gettype($arg), "name"=>self::getVarName(), "value"=>$arg ); } else { self::$debugItemCount++; header( 'Proxy_debug_item_'.self::$debugItemCount.': ' .json_encode( ["category"=>$type, "type"=>gettype($arg), "name"=>self::getVarName(), "value"=>$arg] ) ); header('Proxy_debug_item_count: '.self::$debugItemCount); } } public static function __callStatic($name, $args) { $func = ['info'=>'I', 'warn'=>'W', 'error'=>'E']; if (isset($func[$name])) { self::$offset = 0; self::$varNameString = null; foreach ($args as $key => $arg) { self::func($func[$name], $arg); } } else { throw new Exception('Call to undefined method!', 1); } } /** * groupStart * start record a group * * @access public * @static * * @return null */ public static function groupStart() { self::$start = true; self::$debugGroupCount++; } /** * groupEnd * stop record a group * * @access public * @static * * @return null */ public static function groupEnd() { self::$start = false; header( 'Proxy_debug_group_' .self::$debugGroupCount .': '.json_encode(self::$group) ); header('Proxy_debug_group_count: '.self::$debugGroupCount); self::$group = array(); } }
ログイン後にコピー
2. [文件] main.go ~ 6KB
//Proxy Debug //This simple program is for helping developers debug through http header. //For more detail, see README.md package main import ( "bufio" "encoding/json" "fmt" "io/ioutil" "log" "net/http" "os" "strconv" "strings" ) //color config var color map[string]interface{} //Parse config file func readConfig() { config, err := os.Open("config.ini") if err != nil { log.Fatalln(err) } buf := bufio.NewReader(config) line, _ := buf.ReadString('\n') var jsonData interface{} err = json.Unmarshal([]byte(line), &jsonData) if err != nil { log.Fatalln(err) } var ok bool color, ok = jsonData.(map[string]interface{}) if ok == false { log.Fatalln("Parse config file error, it must be a json string!") } for _, c := range color { if c.(float64) > 37 || c.(float64) < 30 { log.Fatalln("Config error!The valid value is 30-37.") } } item := [5]string{"url", "varName", "varType", "varValue", "group"} for _, i := range item { _, has := color[i] if has == false { log.Fatalln("Losing configuration:", i) } } } func main() { var port int = 8888 if len(os.Args) == 1 { fmt.Println("Listening in default port:8888") } else if os.Args[1] == "--help" { fmt.Println("usage: proxy [-p port]") return } else if len(os.Args) != 3 || os.Args[1] != "-p" { log.Fatalln("Error arguments!Just support '-p port'.") } else { port, err := strconv.Atoi(os.Args[2]) if err != nil && port > 65535 || port < 1024 { log.Fatalln("Error port, it should be 1024-65535, default is 8888.") } } readConfig() http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { r.RequestURI = "" resp, err := http.DefaultClient.Do(r) if err != nil { http.NotFound(w, r) return } defer resp.Body.Close() //Get the debugging information form http header caterory := map[string]int{"I": 34, "W": 33, "E": 31} format := "\t \033[%dm-%s\033[%vm %s\033[%vm%s\033[%vm%s\n" debugItem := make(map[string]map[string]interface{}) debugItemIndex := make([]string, 0, 5) var jsonData interface{} v, okDebugItem := resp.Header["Proxy_debug_item_count"] if okDebugItem { count, _ := strconv.Atoi(v[0]) for i := 1; i <= count; i++ { index := "Proxy_debug_item_" + strconv.Itoa(i) vv, ok := resp.Header[index] if ok { err = json.Unmarshal([]byte(vv[0]), &jsonData) if err != nil { continue } data, ok := jsonData.(map[string]interface{}) if ok == false { continue } debugItemIndex = append(debugItemIndex, index) debugItem[index] = data } } } debugGroup := make(map[string]interface{}) debugGroupIndex := make([]string, 0, 5) v, okDebugGroup := resp.Header["Proxy_debug_group_count"] if okDebugGroup { count, _ := strconv.Atoi(v[0]) for i := 1; i maxLenName { maxLenName = len(v) } v = vm["type"].(string) if len(v) > maxLenType { maxLenType = len(v) } } for _, i := range debugItemIndex { n := debugItem[i]["name"].(string) t := debugItem[i]["type"].(string) c := debugItem[i]["category"].(string) fmt.Printf( format, caterory[c], c, color["varName"], n+strings.Repeat(" ", maxLenName-len(n)+1), color["varType"], t+strings.Repeat(" ", maxLenType-len(t)+1), color["varValue"], strings.Replace(fmt.Sprint(debugItem[i]["value"]), "map", "", 1)) } } if okDebugGroup { if okDebugItem == false { fmt.Printf("\033[%vm%v\n", color["url"], r.URL) } maxLenName := make([]int, len(debugGroupIndex)) maxLenType := make([]int, len(debugGroupIndex)) k := 0 for _, vm := range debugGroup { for _, vv := range vm.([]interface{}) { vk, ok := vv.(map[string]interface{}) if ok == false { continue } v := vk["name"].(string) if len(v) > maxLenName[k] { maxLenName[k] = len(v) } v = vk["type"].(string) if len(v) > maxLenType[k] { maxLenType[k] = len(v) } } k++ } k = 0 for _, i := range debugGroupIndex { fmt.Printf("\t\033[%vm=Group %v=\n", color["group"], k+1) for _, v := range debugGroup[i].([]interface{}) { vk, ok := v.(map[string]interface{}) if ok == false { continue } n := vk["name"].(string) t := vk["type"].(string) c := vk["category"].(string) fmt.Printf( format, caterory[c], c, color["varName"], n+strings.Repeat(" ", maxLenName[k]-len(n)+1), color["varType"], t+strings.Repeat(" ", maxLenType[k]-len(t)+1), color["varValue"], strings.Replace(fmt.Sprint(vk["value"]), "map", "", 1)) } k++ fmt.Printf("\t\033[%vm=GROUP=\n", color["group"]) } } }) http.ListenAndServe(":"+strconv.Itoa(port), nil) }
ログイン後にコピー
3. [图片] screenshot.png
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事
アサシンのクリードシャドウズ:シーシェルリドルソリューション
3週間前
By DDD
Windows11 KB5054979の新しいものと更新の問題を修正する方法
2週間前
By DDD
Atomfallのクレーンコントロールキーカードを見つける場所
3週間前
By DDD
<🎜>:Dead Rails-すべての課題を完了する方法
4週間前
By DDD
Atomfall Guide:アイテムの場所、クエストガイド、およびヒント
4週間前
By DDD

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック
Gmailメールのログイン入り口はどこですか?
7652
15


CakePHP チュートリアル
1392
52


Steamのアカウント名の形式は何ですか
91
11


NYTミニクロスワードの回答
37
110

