dns clickhouse改造
This commit is contained in:
@@ -80,7 +80,7 @@ func (this *StorageManager) Loop() error {
|
||||
|
||||
if int64(policy.Id) == publicPolicyId {
|
||||
this.disableDefaultDB = policy.DisableDefaultDB
|
||||
this.writeTargets = serverconfigs.ParseWriteTargetsFromPolicy(policy.WriteTargets, policy.Type, policy.DisableDefaultDB)
|
||||
this.writeTargets = serverconfigs.ResolveWriteTargetsByType(policy.Type, policy.DisableDefaultDB)
|
||||
foundPolicy = true
|
||||
}
|
||||
}
|
||||
@@ -185,6 +185,9 @@ func (this *StorageManager) WriteTargets() *serverconfigs.AccessLogWriteTargets
|
||||
}
|
||||
|
||||
func (this *StorageManager) createStorage(storageType string, optionsJSON []byte) (StorageInterface, error) {
|
||||
if serverconfigs.IsFileBasedStorageType(storageType) {
|
||||
storageType = serverconfigs.AccessLogStorageTypeFile
|
||||
}
|
||||
switch storageType {
|
||||
case serverconfigs.AccessLogStorageTypeFile:
|
||||
var config = &serverconfigs.AccessLogFileStorageConfig{}
|
||||
|
||||
@@ -85,6 +85,10 @@ func (s *LogsIngestStore) List(ctx context.Context, f ListFilter) (rows []*LogsI
|
||||
if f.Day == "" {
|
||||
return nil, "", fmt.Errorf("clickhouse: day required")
|
||||
}
|
||||
dayNumber, err := normalizeDayNumber(f.Day)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
table := "logs_ingest"
|
||||
if s.client.cfg.Database != "" && s.client.cfg.Database != "default" {
|
||||
table = quoteIdent(s.client.cfg.Database) + "." + quoteIdent("logs_ingest")
|
||||
@@ -92,7 +96,7 @@ func (s *LogsIngestStore) List(ctx context.Context, f ListFilter) (rows []*LogsI
|
||||
table = quoteIdent(table)
|
||||
}
|
||||
|
||||
conditions := []string{"toDate(timestamp) = '" + escapeString(f.Day) + "'"}
|
||||
conditions := []string{"toYYYYMMDD(timestamp) = " + strconv.Itoa(dayNumber)}
|
||||
if f.HourFrom != "" {
|
||||
if _, err := strconv.Atoi(f.HourFrom); err == nil {
|
||||
conditions = append(conditions, "toHour(timestamp) >= "+f.HourFrom)
|
||||
@@ -240,6 +244,22 @@ func escapeString(s string) string {
|
||||
return strings.ReplaceAll(s, "'", "''")
|
||||
}
|
||||
|
||||
func normalizeDayNumber(day string) (int, error) {
|
||||
normalized := strings.TrimSpace(day)
|
||||
if normalized == "" {
|
||||
return 0, fmt.Errorf("clickhouse: day required")
|
||||
}
|
||||
normalized = strings.ReplaceAll(normalized, "-", "")
|
||||
if len(normalized) != 8 {
|
||||
return 0, fmt.Errorf("clickhouse: invalid day '%s'", day)
|
||||
}
|
||||
dayNumber, err := strconv.Atoi(normalized)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("clickhouse: invalid day '%s'", day)
|
||||
}
|
||||
return dayNumber, nil
|
||||
}
|
||||
|
||||
func mapToLogsIngestRow(m map[string]interface{}) *LogsIngestRow {
|
||||
r := &LogsIngestRow{}
|
||||
u64 := func(key string) uint64 {
|
||||
|
||||
375
EdgeAPI/internal/clickhouse/ns_logs_ingest_store.go
Normal file
375
EdgeAPI/internal/clickhouse/ns_logs_ingest_store.go
Normal file
@@ -0,0 +1,375 @@
|
||||
package clickhouse
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
// NSLogsIngestRow 对应 dns_logs_ingest 表一行.
|
||||
type NSLogsIngestRow struct {
|
||||
Timestamp time.Time
|
||||
RequestId string
|
||||
NodeId uint64
|
||||
ClusterId uint64
|
||||
DomainId uint64
|
||||
RecordId uint64
|
||||
RemoteAddr string
|
||||
QuestionName string
|
||||
QuestionType string
|
||||
RecordName string
|
||||
RecordType string
|
||||
RecordValue string
|
||||
Networking string
|
||||
IsRecursive bool
|
||||
Error string
|
||||
NSRouteCodes []string
|
||||
ContentJSON string
|
||||
}
|
||||
|
||||
// NSListFilter DNS 日志查询过滤条件.
|
||||
type NSListFilter struct {
|
||||
Day string
|
||||
Size int64
|
||||
Reverse bool
|
||||
LastRequestId string
|
||||
NSClusterId int64
|
||||
NSNodeId int64
|
||||
NSDomainId int64
|
||||
NSRecordId int64
|
||||
RecordType string
|
||||
Keyword string
|
||||
}
|
||||
|
||||
// NSLogsIngestStore DNS ClickHouse 查询封装.
|
||||
type NSLogsIngestStore struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// NewNSLogsIngestStore 创建 NSLogsIngestStore.
|
||||
func NewNSLogsIngestStore() *NSLogsIngestStore {
|
||||
return &NSLogsIngestStore{client: NewClient()}
|
||||
}
|
||||
|
||||
// Client 返回底层 client.
|
||||
func (s *NSLogsIngestStore) Client() *Client {
|
||||
return s.client
|
||||
}
|
||||
|
||||
// List 列出 DNS 访问日志,返回列表、下一游标与是否有更多.
|
||||
func (s *NSLogsIngestStore) List(ctx context.Context, f NSListFilter) (rows []*NSLogsIngestRow, nextCursor string, hasMore bool, err error) {
|
||||
if !s.client.IsConfigured() {
|
||||
return nil, "", false, fmt.Errorf("clickhouse: not configured")
|
||||
}
|
||||
if f.Day == "" {
|
||||
return nil, "", false, fmt.Errorf("clickhouse: day required")
|
||||
}
|
||||
dayNumber, err := normalizeDayNumber(f.Day)
|
||||
if err != nil {
|
||||
return nil, "", false, err
|
||||
}
|
||||
|
||||
table := quoteIdent("dns_logs_ingest")
|
||||
if s.client.cfg.Database != "" && s.client.cfg.Database != "default" {
|
||||
table = quoteIdent(s.client.cfg.Database) + "." + quoteIdent("dns_logs_ingest")
|
||||
}
|
||||
|
||||
conditions := []string{"toYYYYMMDD(timestamp) = " + strconv.Itoa(dayNumber)}
|
||||
if f.NSClusterId > 0 {
|
||||
conditions = append(conditions, "cluster_id = "+strconv.FormatInt(f.NSClusterId, 10))
|
||||
}
|
||||
if f.NSNodeId > 0 {
|
||||
conditions = append(conditions, "node_id = "+strconv.FormatInt(f.NSNodeId, 10))
|
||||
}
|
||||
if f.NSDomainId > 0 {
|
||||
conditions = append(conditions, "domain_id = "+strconv.FormatInt(f.NSDomainId, 10))
|
||||
}
|
||||
if f.NSRecordId > 0 {
|
||||
conditions = append(conditions, "record_id = "+strconv.FormatInt(f.NSRecordId, 10))
|
||||
}
|
||||
if f.RecordType != "" {
|
||||
conditions = append(conditions, "question_type = '"+escapeString(f.RecordType)+"'")
|
||||
}
|
||||
if f.Keyword != "" {
|
||||
keyword := escapeString(f.Keyword)
|
||||
conditions = append(conditions, fmt.Sprintf("(remote_addr LIKE '%%%s%%' OR question_name LIKE '%%%s%%' OR record_value LIKE '%%%s%%' OR error LIKE '%%%s%%')", keyword, keyword, keyword, keyword))
|
||||
}
|
||||
|
||||
// 游标分页:reverse=false 查更旧,reverse=true 查更新。
|
||||
if f.LastRequestId != "" {
|
||||
if f.Reverse {
|
||||
conditions = append(conditions, "request_id > '"+escapeString(f.LastRequestId)+"'")
|
||||
} else {
|
||||
conditions = append(conditions, "request_id < '"+escapeString(f.LastRequestId)+"'")
|
||||
}
|
||||
}
|
||||
|
||||
orderDir := "DESC"
|
||||
if f.Reverse {
|
||||
orderDir = "ASC"
|
||||
}
|
||||
|
||||
limit := f.Size
|
||||
if limit <= 0 {
|
||||
limit = 20
|
||||
}
|
||||
if limit > 1000 {
|
||||
limit = 1000
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(
|
||||
"SELECT timestamp, request_id, node_id, cluster_id, domain_id, record_id, remote_addr, question_name, question_type, record_name, record_type, record_value, networking, is_recursive, error, ns_route_codes, content_json FROM %s WHERE %s ORDER BY timestamp %s, request_id %s LIMIT %d",
|
||||
table,
|
||||
strings.Join(conditions, " AND "),
|
||||
orderDir,
|
||||
orderDir,
|
||||
limit+1,
|
||||
)
|
||||
|
||||
var rawRows []map[string]interface{}
|
||||
if err = s.client.Query(ctx, query, &rawRows); err != nil {
|
||||
return nil, "", false, err
|
||||
}
|
||||
|
||||
rows = make([]*NSLogsIngestRow, 0, len(rawRows))
|
||||
for _, rawRow := range rawRows {
|
||||
row := mapToNSLogsIngestRow(rawRow)
|
||||
if row != nil {
|
||||
rows = append(rows, row)
|
||||
}
|
||||
}
|
||||
|
||||
hasMore = len(rows) > int(limit)
|
||||
if hasMore {
|
||||
nextCursor = rows[limit].RequestId
|
||||
rows = rows[:limit]
|
||||
} else if len(rows) > 0 {
|
||||
nextCursor = rows[len(rows)-1].RequestId
|
||||
}
|
||||
|
||||
if f.Reverse {
|
||||
for left, right := 0, len(rows)-1; left < right; left, right = left+1, right-1 {
|
||||
rows[left], rows[right] = rows[right], rows[left]
|
||||
}
|
||||
if len(rows) > 0 {
|
||||
nextCursor = rows[0].RequestId
|
||||
}
|
||||
}
|
||||
|
||||
return rows, nextCursor, hasMore, nil
|
||||
}
|
||||
|
||||
// FindByRequestId 按 request_id 查单条 DNS 日志.
|
||||
func (s *NSLogsIngestStore) FindByRequestId(ctx context.Context, requestId string) (*NSLogsIngestRow, error) {
|
||||
if !s.client.IsConfigured() {
|
||||
return nil, fmt.Errorf("clickhouse: not configured")
|
||||
}
|
||||
if requestId == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
table := quoteIdent("dns_logs_ingest")
|
||||
if s.client.cfg.Database != "" && s.client.cfg.Database != "default" {
|
||||
table = quoteIdent(s.client.cfg.Database) + "." + quoteIdent("dns_logs_ingest")
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(
|
||||
"SELECT timestamp, request_id, node_id, cluster_id, domain_id, record_id, remote_addr, question_name, question_type, record_name, record_type, record_value, networking, is_recursive, error, ns_route_codes, content_json FROM %s WHERE request_id = '%s' LIMIT 1",
|
||||
table,
|
||||
escapeString(requestId),
|
||||
)
|
||||
|
||||
var rawRows []map[string]interface{}
|
||||
if err := s.client.Query(ctx, query, &rawRows); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(rawRows) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return mapToNSLogsIngestRow(rawRows[0]), nil
|
||||
}
|
||||
|
||||
func mapToNSLogsIngestRow(row map[string]interface{}) *NSLogsIngestRow {
|
||||
result := &NSLogsIngestRow{}
|
||||
|
||||
u64 := func(key string) uint64 {
|
||||
value, ok := row[key]
|
||||
if !ok || value == nil {
|
||||
return 0
|
||||
}
|
||||
switch typed := value.(type) {
|
||||
case float64:
|
||||
return uint64(typed)
|
||||
case string:
|
||||
number, _ := strconv.ParseUint(typed, 10, 64)
|
||||
return number
|
||||
case json.Number:
|
||||
number, _ := typed.Int64()
|
||||
return uint64(number)
|
||||
case int64:
|
||||
return uint64(typed)
|
||||
case uint64:
|
||||
return typed
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
str := func(key string) string {
|
||||
value, ok := row[key]
|
||||
if !ok || value == nil {
|
||||
return ""
|
||||
}
|
||||
switch typed := value.(type) {
|
||||
case string:
|
||||
return typed
|
||||
case json.Number:
|
||||
return typed.String()
|
||||
default:
|
||||
return fmt.Sprintf("%v", typed)
|
||||
}
|
||||
}
|
||||
|
||||
ts := func(key string) time.Time {
|
||||
value, ok := row[key]
|
||||
if !ok || value == nil {
|
||||
return time.Time{}
|
||||
}
|
||||
switch typed := value.(type) {
|
||||
case string:
|
||||
if typed == "" {
|
||||
return time.Time{}
|
||||
}
|
||||
layouts := []string{
|
||||
"2006-01-02 15:04:05",
|
||||
time.RFC3339,
|
||||
"2006-01-02T15:04:05",
|
||||
}
|
||||
for _, layout := range layouts {
|
||||
if parsed, err := time.Parse(layout, typed); err == nil {
|
||||
return parsed
|
||||
}
|
||||
}
|
||||
case float64:
|
||||
return time.Unix(int64(typed), 0)
|
||||
case json.Number:
|
||||
number, _ := typed.Int64()
|
||||
return time.Unix(number, 0)
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
boolValue := func(key string) bool {
|
||||
value, ok := row[key]
|
||||
if !ok || value == nil {
|
||||
return false
|
||||
}
|
||||
switch typed := value.(type) {
|
||||
case bool:
|
||||
return typed
|
||||
case float64:
|
||||
return typed > 0
|
||||
case int64:
|
||||
return typed > 0
|
||||
case uint64:
|
||||
return typed > 0
|
||||
case string:
|
||||
switch strings.ToLower(strings.TrimSpace(typed)) {
|
||||
case "1", "true", "yes":
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
parseStringArray := func(key string) []string {
|
||||
value, ok := row[key]
|
||||
if !ok || value == nil {
|
||||
return nil
|
||||
}
|
||||
switch typed := value.(type) {
|
||||
case []string:
|
||||
return typed
|
||||
case []interface{}:
|
||||
result := make([]string, 0, len(typed))
|
||||
for _, one := range typed {
|
||||
if one == nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, fmt.Sprintf("%v", one))
|
||||
}
|
||||
return result
|
||||
case string:
|
||||
if typed == "" {
|
||||
return nil
|
||||
}
|
||||
var result []string
|
||||
if json.Unmarshal([]byte(typed), &result) == nil {
|
||||
return result
|
||||
}
|
||||
return []string{typed}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
result.Timestamp = ts("timestamp")
|
||||
result.RequestId = str("request_id")
|
||||
result.NodeId = u64("node_id")
|
||||
result.ClusterId = u64("cluster_id")
|
||||
result.DomainId = u64("domain_id")
|
||||
result.RecordId = u64("record_id")
|
||||
result.RemoteAddr = str("remote_addr")
|
||||
result.QuestionName = str("question_name")
|
||||
result.QuestionType = str("question_type")
|
||||
result.RecordName = str("record_name")
|
||||
result.RecordType = str("record_type")
|
||||
result.RecordValue = str("record_value")
|
||||
result.Networking = str("networking")
|
||||
result.IsRecursive = boolValue("is_recursive")
|
||||
result.Error = str("error")
|
||||
result.NSRouteCodes = parseStringArray("ns_route_codes")
|
||||
result.ContentJSON = str("content_json")
|
||||
return result
|
||||
}
|
||||
|
||||
// NSRowToPB 将 ClickHouse 行转换为 pb.NSAccessLog.
|
||||
func NSRowToPB(row *NSLogsIngestRow) *pb.NSAccessLog {
|
||||
if row == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
log := &pb.NSAccessLog{
|
||||
NsNodeId: int64(row.NodeId),
|
||||
NsDomainId: int64(row.DomainId),
|
||||
NsRecordId: int64(row.RecordId),
|
||||
NsRouteCodes: row.NSRouteCodes,
|
||||
RemoteAddr: row.RemoteAddr,
|
||||
QuestionName: row.QuestionName,
|
||||
QuestionType: row.QuestionType,
|
||||
RecordName: row.RecordName,
|
||||
RecordType: row.RecordType,
|
||||
RecordValue: row.RecordValue,
|
||||
Networking: row.Networking,
|
||||
Timestamp: row.Timestamp.Unix(),
|
||||
RequestId: row.RequestId,
|
||||
Error: row.Error,
|
||||
IsRecursive: row.IsRecursive,
|
||||
}
|
||||
if !row.Timestamp.IsZero() {
|
||||
log.TimeLocal = row.Timestamp.Format("2/Jan/2006:15:04:05 -0700")
|
||||
}
|
||||
|
||||
if row.ContentJSON != "" {
|
||||
contentLog := &pb.NSAccessLog{}
|
||||
if json.Unmarshal([]byte(row.ContentJSON), contentLog) == nil {
|
||||
contentLog.RequestId = row.RequestId
|
||||
return contentLog
|
||||
}
|
||||
}
|
||||
|
||||
return log
|
||||
}
|
||||
@@ -108,6 +108,7 @@ func (this *HTTPAccessLogPolicyDAO) FindAllEnabledAndOnPolicies(tx *dbs.Tx) (res
|
||||
|
||||
// CreatePolicy 创建策略
|
||||
func (this *HTTPAccessLogPolicyDAO) CreatePolicy(tx *dbs.Tx, name string, policyType string, optionsJSON []byte, condsJSON []byte, isPublic bool, firewallOnly bool, disableDefaultDB bool, writeTargetsJSON []byte) (policyId int64, err error) {
|
||||
_ = writeTargetsJSON
|
||||
var op = NewHTTPAccessLogPolicyOperator()
|
||||
op.Name = name
|
||||
op.Type = policyType
|
||||
@@ -121,15 +122,14 @@ func (this *HTTPAccessLogPolicyDAO) CreatePolicy(tx *dbs.Tx, name string, policy
|
||||
op.IsOn = true
|
||||
op.FirewallOnly = firewallOnly
|
||||
op.DisableDefaultDB = disableDefaultDB
|
||||
if len(writeTargetsJSON) > 0 {
|
||||
op.WriteTargets = writeTargetsJSON
|
||||
}
|
||||
op.WriteTargets = dbs.SQL("NULL")
|
||||
op.State = HTTPAccessLogPolicyStateEnabled
|
||||
return this.SaveInt64(tx, op)
|
||||
}
|
||||
|
||||
// UpdatePolicy 修改策略
|
||||
func (this *HTTPAccessLogPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, name string, policyType string, optionsJSON []byte, condsJSON []byte, isPublic bool, firewallOnly bool, disableDefaultDB bool, writeTargetsJSON []byte, isOn bool) error {
|
||||
_ = writeTargetsJSON
|
||||
if policyId <= 0 {
|
||||
return errors.New("invalid policyId")
|
||||
}
|
||||
@@ -167,9 +167,7 @@ func (this *HTTPAccessLogPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, nam
|
||||
op.IsPublic = isPublic
|
||||
op.FirewallOnly = firewallOnly
|
||||
op.DisableDefaultDB = disableDefaultDB
|
||||
if len(writeTargetsJSON) > 0 {
|
||||
op.WriteTargets = writeTargetsJSON
|
||||
}
|
||||
op.WriteTargets = dbs.SQL("NULL")
|
||||
op.IsOn = isOn
|
||||
return this.Save(tx, op)
|
||||
}
|
||||
|
||||
22
EdgeAPI/internal/db/models/http_access_log_policy_utils.go
Normal file
22
EdgeAPI/internal/db/models/http_access_log_policy_utils.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
)
|
||||
|
||||
// ParseHTTPAccessLogPolicyFilePath 提取访问日志策略中的文件路径(所有 file* 类型有效)。
|
||||
func ParseHTTPAccessLogPolicyFilePath(policy *HTTPAccessLogPolicy) string {
|
||||
if policy == nil || !serverconfigs.IsFileBasedStorageType(policy.Type) || len(policy.Options) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
config := &serverconfigs.AccessLogFileStorageConfig{}
|
||||
if err := json.Unmarshal(policy.Options, config); err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strings.TrimSpace(config.Path)
|
||||
}
|
||||
@@ -1174,7 +1174,8 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, dataMap *shared
|
||||
if publicPolicyId > 0 {
|
||||
publicPolicy, _ := SharedHTTPAccessLogPolicyDAO.FindEnabledHTTPAccessLogPolicy(tx, publicPolicyId)
|
||||
if publicPolicy != nil {
|
||||
config.GlobalServerConfig.HTTPAccessLog.WriteTargets = serverconfigs.ParseWriteTargetsFromPolicy(publicPolicy.WriteTargets, publicPolicy.Type, publicPolicy.DisableDefaultDB)
|
||||
config.GlobalServerConfig.HTTPAccessLog.WriteTargets = serverconfigs.ResolveWriteTargetsByType(publicPolicy.Type, publicPolicy.DisableDefaultDB)
|
||||
config.GlobalServerConfig.HTTPAccessLog.FilePath = ParseHTTPAccessLogPolicyFilePath(publicPolicy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,6 +472,16 @@ func (this *NSNodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64) (*dnsconfigs.
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
publicPolicyId, _ := SharedHTTPAccessLogPolicyDAO.FindCurrentPublicPolicyId(tx)
|
||||
if publicPolicyId > 0 {
|
||||
publicPolicy, _ := SharedHTTPAccessLogPolicyDAO.FindEnabledHTTPAccessLogPolicy(tx, publicPolicyId)
|
||||
if publicPolicy != nil {
|
||||
config.AccessLogWriteTargets = serverconfigs.ResolveWriteTargetsByType(publicPolicy.Type, publicPolicy.DisableDefaultDB)
|
||||
config.AccessLogFilePath = ParseHTTPAccessLogPolicyFilePath(publicPolicy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 递归DNS配置
|
||||
if IsNotNull(cluster.Recursion) {
|
||||
|
||||
@@ -4,6 +4,7 @@ package nameservers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/clickhouse"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/nameservers"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
|
||||
@@ -29,11 +30,13 @@ func (this *NSAccessLogService) CreateNSAccessLogs(ctx context.Context, req *pb.
|
||||
return &pb.CreateNSAccessLogsResponse{}, nil
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
if this.canWriteNSAccessLogsToDB() {
|
||||
var tx = this.NullTx()
|
||||
|
||||
err = models.SharedNSAccessLogDAO.CreateNSAccessLogs(tx, req.NsAccessLogs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
err = models.SharedNSAccessLogDAO.CreateNSAccessLogs(tx, req.NsAccessLogs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &pb.CreateNSAccessLogsResponse{}, nil
|
||||
@@ -54,6 +57,34 @@ func (this *NSAccessLogService) ListNSAccessLogs(ctx context.Context, req *pb.Li
|
||||
// TODO 检查权限
|
||||
}
|
||||
|
||||
store := clickhouse.NewNSLogsIngestStore()
|
||||
canReadFromClickHouse := this.shouldReadNSAccessLogsFromClickHouse() && store.Client().IsConfigured() && req.Day != ""
|
||||
canReadFromMySQL := this.shouldReadNSAccessLogsFromMySQL()
|
||||
if canReadFromClickHouse {
|
||||
resp, listErr := this.listNSAccessLogsFromClickHouse(ctx, store, req)
|
||||
if listErr == nil && resp != nil {
|
||||
return resp, nil
|
||||
}
|
||||
if !canReadFromMySQL {
|
||||
if listErr != nil {
|
||||
return nil, listErr
|
||||
}
|
||||
return &pb.ListNSAccessLogsResponse{
|
||||
NsAccessLogs: []*pb.NSAccessLog{},
|
||||
HasMore: false,
|
||||
RequestId: "",
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
if !canReadFromMySQL {
|
||||
return &pb.ListNSAccessLogsResponse{
|
||||
NsAccessLogs: []*pb.NSAccessLog{},
|
||||
HasMore: false,
|
||||
RequestId: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
accessLogs, requestId, hasMore, err := models.SharedNSAccessLogDAO.ListAccessLogs(tx, req.RequestId, req.Size, req.Day, req.NsClusterId, req.NsNodeId, req.NsDomainId, req.NsRecordId, req.RecordType, req.Keyword, req.Reverse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -67,23 +98,9 @@ func (this *NSAccessLogService) ListNSAccessLogs(ctx context.Context, req *pb.Li
|
||||
}
|
||||
|
||||
// 线路
|
||||
if len(a.NsRouteCodes) > 0 {
|
||||
for _, routeCode := range a.NsRouteCodes {
|
||||
route, err := nameservers.SharedNSRouteDAO.FindEnabledRouteWithCode(nil, routeCode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if route != nil {
|
||||
a.NsRoutes = append(a.NsRoutes, &pb.NSRoute{
|
||||
Id: types.Int64(route.Id),
|
||||
IsOn: route.IsOn,
|
||||
Name: route.Name,
|
||||
Code: routeCode,
|
||||
NsCluster: nil,
|
||||
NsDomain: nil,
|
||||
})
|
||||
}
|
||||
}
|
||||
err = this.fillNSRoutes(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result = append(result, a)
|
||||
@@ -104,6 +121,31 @@ func (this *NSAccessLogService) FindNSAccessLog(ctx context.Context, req *pb.Fin
|
||||
return nil, err
|
||||
}
|
||||
|
||||
store := clickhouse.NewNSLogsIngestStore()
|
||||
canReadFromClickHouse := this.shouldReadNSAccessLogsFromClickHouse() && store.Client().IsConfigured()
|
||||
canReadFromMySQL := this.shouldReadNSAccessLogsFromMySQL()
|
||||
if canReadFromClickHouse {
|
||||
row, findErr := store.FindByRequestId(ctx, req.RequestId)
|
||||
if findErr != nil {
|
||||
if !canReadFromMySQL {
|
||||
return nil, findErr
|
||||
}
|
||||
} else if row != nil {
|
||||
a := clickhouse.NSRowToPB(row)
|
||||
if a != nil {
|
||||
err = this.fillNSRoutes(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &pb.FindNSAccessLogResponse{NsAccessLog: a}, nil
|
||||
}
|
||||
}
|
||||
|
||||
if !canReadFromMySQL {
|
||||
return &pb.FindNSAccessLogResponse{NsAccessLog: nil}, nil
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
accessLog, err := models.SharedNSAccessLogDAO.FindAccessLogWithRequestId(tx, req.RequestId)
|
||||
@@ -123,5 +165,70 @@ func (this *NSAccessLogService) FindNSAccessLog(ctx context.Context, req *pb.Fin
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = this.fillNSRoutes(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.FindNSAccessLogResponse{NsAccessLog: a}, nil
|
||||
}
|
||||
|
||||
func (this *NSAccessLogService) listNSAccessLogsFromClickHouse(ctx context.Context, store *clickhouse.NSLogsIngestStore, req *pb.ListNSAccessLogsRequest) (*pb.ListNSAccessLogsResponse, error) {
|
||||
rows, nextCursor, hasMore, err := store.List(ctx, clickhouse.NSListFilter{
|
||||
Day: req.Day,
|
||||
Size: req.Size,
|
||||
Reverse: req.Reverse,
|
||||
LastRequestId: req.RequestId,
|
||||
NSClusterId: req.NsClusterId,
|
||||
NSNodeId: req.NsNodeId,
|
||||
NSDomainId: req.NsDomainId,
|
||||
NSRecordId: req.NsRecordId,
|
||||
RecordType: req.RecordType,
|
||||
Keyword: req.Keyword,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*pb.NSAccessLog, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
a := clickhouse.NSRowToPB(row)
|
||||
if a == nil {
|
||||
continue
|
||||
}
|
||||
err = this.fillNSRoutes(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, a)
|
||||
}
|
||||
|
||||
return &pb.ListNSAccessLogsResponse{
|
||||
NsAccessLogs: result,
|
||||
HasMore: hasMore,
|
||||
RequestId: nextCursor,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (this *NSAccessLogService) fillNSRoutes(accessLog *pb.NSAccessLog) error {
|
||||
if accessLog == nil || len(accessLog.NsRouteCodes) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, routeCode := range accessLog.NsRouteCodes {
|
||||
route, err := nameservers.SharedNSRouteDAO.FindEnabledRouteWithCode(nil, routeCode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if route != nil {
|
||||
accessLog.NsRoutes = append(accessLog.NsRoutes, &pb.NSRoute{
|
||||
Id: types.Int64(route.Id),
|
||||
IsOn: route.IsOn,
|
||||
Name: route.Name,
|
||||
Code: routeCode,
|
||||
NsCluster: nil,
|
||||
NsDomain: nil,
|
||||
})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
//go:build plus
|
||||
|
||||
package nameservers
|
||||
|
||||
import "github.com/TeaOSLab/EdgeAPI/internal/accesslogs"
|
||||
|
||||
func (this *NSAccessLogService) canWriteNSAccessLogsToDB() bool {
|
||||
return accesslogs.SharedStorageManager.WriteMySQL()
|
||||
}
|
||||
|
||||
func (this *NSAccessLogService) shouldReadNSAccessLogsFromClickHouse() bool {
|
||||
return accesslogs.SharedStorageManager.WriteClickHouse()
|
||||
}
|
||||
|
||||
func (this *NSAccessLogService) shouldReadNSAccessLogsFromMySQL() bool {
|
||||
return accesslogs.SharedStorageManager.WriteMySQL()
|
||||
}
|
||||
@@ -8,12 +8,27 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/accesslogs"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
)
|
||||
|
||||
type HTTPAccessLogPolicyService struct {
|
||||
BaseService
|
||||
}
|
||||
|
||||
func (this *HTTPAccessLogPolicyService) normalizeStorageTypeAndTargets(policyType string, writeTargetsJSON []byte, disableDefaultDB bool) (string, []byte) {
|
||||
_ = writeTargetsJSON
|
||||
_ = disableDefaultDB
|
||||
|
||||
// 兼容旧前端/缓存可能传来的历史类型编码
|
||||
switch policyType {
|
||||
case "clickhouse":
|
||||
policyType = serverconfigs.AccessLogStorageTypeFileClickhouse
|
||||
case "mysql_clickhouse":
|
||||
policyType = serverconfigs.AccessLogStorageTypeFileMySQLClickhouse
|
||||
}
|
||||
return policyType, nil
|
||||
}
|
||||
|
||||
// CountAllHTTPAccessLogPolicies 计算访问日志策略数量
|
||||
func (this *HTTPAccessLogPolicyService) CountAllHTTPAccessLogPolicies(ctx context.Context, req *pb.CountAllHTTPAccessLogPoliciesRequest) (*pb.RPCCountResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
@@ -53,7 +68,7 @@ func (this *HTTPAccessLogPolicyService) ListHTTPAccessLogPolicies(ctx context.Co
|
||||
IsPublic: policy.IsPublic,
|
||||
FirewallOnly: policy.FirewallOnly == 1,
|
||||
DisableDefaultDB: policy.DisableDefaultDB,
|
||||
WriteTargetsJSON: policy.WriteTargets,
|
||||
WriteTargetsJSON: nil,
|
||||
})
|
||||
}
|
||||
return &pb.ListHTTPAccessLogPoliciesResponse{HttpAccessLogPolicies: pbPolicies}, nil
|
||||
@@ -76,8 +91,10 @@ func (this *HTTPAccessLogPolicyService) CreateHTTPAccessLogPolicy(ctx context.Co
|
||||
}
|
||||
}
|
||||
|
||||
policyType, writeTargetsJSON := this.normalizeStorageTypeAndTargets(req.Type, req.WriteTargetsJSON, req.DisableDefaultDB)
|
||||
|
||||
// 创建
|
||||
policyId, err := models.SharedHTTPAccessLogPolicyDAO.CreatePolicy(tx, req.Name, req.Type, req.OptionsJSON, req.CondsJSON, req.IsPublic, req.FirewallOnly, req.DisableDefaultDB, req.WriteTargetsJSON)
|
||||
policyId, err := models.SharedHTTPAccessLogPolicyDAO.CreatePolicy(tx, req.Name, policyType, req.OptionsJSON, req.CondsJSON, req.IsPublic, req.FirewallOnly, req.DisableDefaultDB, writeTargetsJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -101,8 +118,10 @@ func (this *HTTPAccessLogPolicyService) UpdateHTTPAccessLogPolicy(ctx context.Co
|
||||
}
|
||||
}
|
||||
|
||||
policyType, writeTargetsJSON := this.normalizeStorageTypeAndTargets(req.Type, req.WriteTargetsJSON, req.DisableDefaultDB)
|
||||
|
||||
// 保存修改
|
||||
err = models.SharedHTTPAccessLogPolicyDAO.UpdatePolicy(tx, req.HttpAccessLogPolicyId, req.Name, req.Type, req.OptionsJSON, req.CondsJSON, req.IsPublic, req.FirewallOnly, req.DisableDefaultDB, req.WriteTargetsJSON, req.IsOn)
|
||||
err = models.SharedHTTPAccessLogPolicyDAO.UpdatePolicy(tx, req.HttpAccessLogPolicyId, req.Name, policyType, req.OptionsJSON, req.CondsJSON, req.IsPublic, req.FirewallOnly, req.DisableDefaultDB, writeTargetsJSON, req.IsOn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -134,7 +153,7 @@ func (this *HTTPAccessLogPolicyService) FindHTTPAccessLogPolicy(ctx context.Cont
|
||||
IsPublic: policy.IsPublic,
|
||||
FirewallOnly: policy.FirewallOnly == 1,
|
||||
DisableDefaultDB: policy.DisableDefaultDB,
|
||||
WriteTargetsJSON: policy.WriteTargets,
|
||||
WriteTargetsJSON: nil,
|
||||
}}, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user