@@ -8,9 +8,10 @@ import (
88 "github.com/github/gh-aw-mcpg/internal/logger"
99)
1010
11- // FilteredItemLogEntry is a structured log entry for a DIFC-filtered item.
12- // It captures enough context to identify the object, understand why it was
13- // filtered, and link back to it in a post-processing report.
11+ // FilteredItemLogEntry is the structured log record emitted for each item
12+ // removed by DIFC filtering. It is written as JSON to the unified and
13+ // per-server text log files under the [DIFC-FILTERED] marker so that filter
14+ // events can be correlated with the MCP request/response that triggered them.
1415type FilteredItemLogEntry struct {
1516 ServerID string `json:"server_id"`
1617 ToolName string `json:"tool_name"`
@@ -26,26 +27,24 @@ type FilteredItemLogEntry struct {
2627}
2728
2829// logFilteredItems logs structured details for every item removed by DIFC filtering.
29- // Each item is logged individually to the configured logger outputs so that
30- // post-processing tools can reconstruct exactly what was filtered and why.
30+ // Each item is written as a [DIFC-FILTERED] JSON entry to both the unified and
31+ // per-server text log files (via LogInfoWithServer), and as a DIFC_FILTERED entry
32+ // in the JSONL log.
3133func logFilteredItems (serverID , toolName string , filtered * difc.FilteredCollectionLabeledData ) {
3234 for _ , detail := range filtered .Filtered {
3335 entry := buildFilteredItemLogEntry (serverID , toolName , detail )
34-
35- entryJSON , err := json .Marshal (entry )
36+ b , err := json .Marshal (entry )
3637 if err != nil {
37- logger .LogWarnWithServer (serverID , "difc" ,
38- "[DIFC-FILTERED] %s | %s | description=%s | reason=%s (json marshal failed: %v)" ,
39- serverID , toolName , entry .Description , entry .Reason , err )
38+ logger .LogInfoWithServer (serverID , "difc" , "Failed to marshal filtered item log entry: %v" , err )
4039 continue
4140 }
42-
43- logger .LogInfoWithServer (serverID , "difc" ,
44- "[DIFC-FILTERED] %s" , string ( entryJSON ))
41+ jsonStr := string ( b )
42+ logger .LogInfoWithServer (serverID , "difc" , "[DIFC-FILTERED] %s" , jsonStr )
43+ logger . LogDifcFilteredItem ( entry . toJSONLFilteredItem ( ))
4544 }
4645}
4746
48- // buildFilteredItemLogEntry constructs a structured log entry from a filtered item.
47+ // buildFilteredItemLogEntry constructs a FilteredItemLogEntry from a filtered item.
4948func buildFilteredItemLogEntry (serverID , toolName string , detail difc.FilteredItemDetail ) FilteredItemLogEntry {
5049 entry := FilteredItemLogEntry {
5150 ServerID : serverID ,
@@ -72,6 +71,24 @@ func buildFilteredItemLogEntry(serverID, toolName string, detail difc.FilteredIt
7271 return entry
7372}
7473
74+ // toJSONLFilteredItem converts a FilteredItemLogEntry to a logger.JSONLFilteredItem
75+ // for writing to the JSONL log.
76+ func (e FilteredItemLogEntry ) toJSONLFilteredItem () * logger.JSONLFilteredItem {
77+ return & logger.JSONLFilteredItem {
78+ ServerID : e .ServerID ,
79+ ToolName : e .ToolName ,
80+ Description : e .Description ,
81+ Reason : e .Reason ,
82+ SecrecyTags : e .SecrecyTags ,
83+ IntegrityTags : e .IntegrityTags ,
84+ AuthorAssociation : e .AuthorAssociation ,
85+ AuthorLogin : e .AuthorLogin ,
86+ HTMLURL : e .HTMLURL ,
87+ Number : e .Number ,
88+ SHA : e .SHA ,
89+ }
90+ }
91+
7592// tagsToStrings converts DIFC tags to string slice.
7693func tagsToStrings (tags []difc.Tag ) []string {
7794 s := make ([]string , len (tags ))
@@ -96,13 +113,11 @@ func getStringField(m map[string]interface{}, fields ...string) string {
96113
97114// extractAuthorLogin extracts the author login from nested user/author objects.
98115func extractAuthorLogin (m map [string ]interface {}) string {
99- // Try user.login (issues, PRs)
100116 if user , ok := m ["user" ].(map [string ]interface {}); ok {
101117 if login , ok := user ["login" ].(string ); ok {
102118 return login
103119 }
104120 }
105- // Try author.login (commits)
106121 if author , ok := m ["author" ].(map [string ]interface {}); ok {
107122 if login , ok := author ["login" ].(string ); ok {
108123 return login
@@ -112,7 +127,6 @@ func extractAuthorLogin(m map[string]interface{}) string {
112127}
113128
114129// extractNumberField extracts the item number as a string.
115- // GitHub API returns numbers as float64 from JSON parsing.
116130func extractNumberField (m map [string ]interface {}) string {
117131 if n , ok := m ["number" ]; ok {
118132 switch v := n .(type ) {
0 commit comments