You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by wa...@apache.org on 2025/08/04 12:23:21 UTC

(incubator-devlake) branch main updated: fix(q_dev): fix task logging (#8503)

This is an automated email from the ASF dual-hosted git repository.

warren pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git


The following commit(s) were added to refs/heads/main by this push:
     new d4a195761 fix(q_dev): fix task logging (#8503)
d4a195761 is described below

commit d4a19576182b61b3db17460058f3ccba946e991a
Author: DiscreteTom <di...@outlook.com>
AuthorDate: Mon Aug 4 20:23:16 2025 +0800

    fix(q_dev): fix task logging (#8503)
---
 backend/plugins/q_dev/api/connection_test.go       |   4 +-
 backend/plugins/q_dev/impl/impl.go                 |   1 +
 .../migrationscripts/archived/user_metrics.go      |   3 +-
 backend/plugins/q_dev/models/user_data_test.go     |  98 +++++------
 backend/plugins/q_dev/tasks/s3_data_extractor.go   |  21 ++-
 .../plugins/q_dev/tasks/s3_data_extractor_test.go  | 188 ++++++++++++++-------
 6 files changed, 190 insertions(+), 125 deletions(-)

diff --git a/backend/plugins/q_dev/api/connection_test.go b/backend/plugins/q_dev/api/connection_test.go
index 916fbd155..6c39dee3f 100644
--- a/backend/plugins/q_dev/api/connection_test.go
+++ b/backend/plugins/q_dev/api/connection_test.go
@@ -231,11 +231,11 @@ func TestConnectionSanitization_PreservesIdentityStore(t *testing.T) {
 
 	// Secret should be sanitized
 	assert.NotEqual(t, "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", sanitized.SecretAccessKey)
-	
+
 	// Identity Store fields should be preserved
 	assert.Equal(t, "d-1234567890", sanitized.IdentityStoreId)
 	assert.Equal(t, "us-west-2", sanitized.IdentityStoreRegion)
-	
+
 	// Other fields should be preserved
 	assert.Equal(t, "AKIAIOSFODNN7EXAMPLE", sanitized.AccessKeyId)
 	assert.Equal(t, "us-east-1", sanitized.Region)
diff --git a/backend/plugins/q_dev/impl/impl.go b/backend/plugins/q_dev/impl/impl.go
index 5cf8bf393..b2568334b 100644
--- a/backend/plugins/q_dev/impl/impl.go
+++ b/backend/plugins/q_dev/impl/impl.go
@@ -19,6 +19,7 @@ package impl
 
 import (
 	"fmt"
+
 	"github.com/apache/incubator-devlake/core/context"
 	"github.com/apache/incubator-devlake/core/dal"
 	"github.com/apache/incubator-devlake/core/errors"
diff --git a/backend/plugins/q_dev/models/migrationscripts/archived/user_metrics.go b/backend/plugins/q_dev/models/migrationscripts/archived/user_metrics.go
index d26b75aea..be948feea 100644
--- a/backend/plugins/q_dev/models/migrationscripts/archived/user_metrics.go
+++ b/backend/plugins/q_dev/models/migrationscripts/archived/user_metrics.go
@@ -18,8 +18,9 @@ limitations under the License.
 package archived
 
 import (
-	"github.com/apache/incubator-devlake/core/models/migrationscripts/archived"
 	"time"
+
+	"github.com/apache/incubator-devlake/core/models/migrationscripts/archived"
 )
 
 // QDevUserMetrics 存储按用户聚合的指标数据
diff --git a/backend/plugins/q_dev/models/user_data_test.go b/backend/plugins/q_dev/models/user_data_test.go
index d45d1748f..74d5dfcfe 100644
--- a/backend/plugins/q_dev/models/user_data_test.go
+++ b/backend/plugins/q_dev/models/user_data_test.go
@@ -20,7 +20,7 @@ package models
 import (
 	"testing"
 	"time"
-	
+
 	"github.com/stretchr/testify/assert"
 )
 
@@ -28,59 +28,59 @@ func TestQDevUserDataAllMetrics(t *testing.T) {
 	// Create a test user data object with all metrics
 	userData := &QDevUserData{
 		ConnectionId: 1,
-		UserId: "test-user-id",
-		Date: time.Now(),
-		DisplayName: "Test User",
-		
+		UserId:       "test-user-id",
+		Date:         time.Now(),
+		DisplayName:  "Test User",
+
 		// Set values for existing metrics
-		CodeReview_FindingsCount: 10,
-		CodeReview_SucceededEventCount: 11,
-		InlineChat_AcceptanceEventCount: 12,
-		InlineChat_AcceptedLineAdditions: 13,
-		InlineChat_AcceptedLineDeletions: 14,
-		InlineChat_DismissalEventCount: 15,
+		CodeReview_FindingsCount:          10,
+		CodeReview_SucceededEventCount:    11,
+		InlineChat_AcceptanceEventCount:   12,
+		InlineChat_AcceptedLineAdditions:  13,
+		InlineChat_AcceptedLineDeletions:  14,
+		InlineChat_DismissalEventCount:    15,
 		InlineChat_DismissedLineAdditions: 16,
 		InlineChat_DismissedLineDeletions: 17,
-		InlineChat_RejectedLineAdditions: 18,
-		InlineChat_RejectedLineDeletions: 19,
-		InlineChat_RejectionEventCount: 20,
-		InlineChat_TotalEventCount: 21,
-		Inline_AICodeLines: 22,
-		Inline_AcceptanceCount: 23,
-		Inline_SuggestionsCount: 24,
-		
+		InlineChat_RejectedLineAdditions:  18,
+		InlineChat_RejectedLineDeletions:  19,
+		InlineChat_RejectionEventCount:    20,
+		InlineChat_TotalEventCount:        21,
+		Inline_AICodeLines:                22,
+		Inline_AcceptanceCount:            23,
+		Inline_SuggestionsCount:           24,
+
 		// Set values for new metrics
-		Chat_AICodeLines: 25,
-		Chat_MessagesInteracted: 26,
-		Chat_MessagesSent: 27,
-		CodeFix_AcceptanceEventCount: 28,
-		CodeFix_AcceptedLines: 29,
-		CodeFix_GeneratedLines: 30,
-		CodeFix_GenerationEventCount: 31,
-		CodeReview_FailedEventCount: 32,
-		Dev_AcceptanceEventCount: 33,
-		Dev_AcceptedLines: 34,
-		Dev_GeneratedLines: 35,
-		Dev_GenerationEventCount: 36,
-		DocGeneration_AcceptedFileUpdates: 37,
+		Chat_AICodeLines:                     25,
+		Chat_MessagesInteracted:              26,
+		Chat_MessagesSent:                    27,
+		CodeFix_AcceptanceEventCount:         28,
+		CodeFix_AcceptedLines:                29,
+		CodeFix_GeneratedLines:               30,
+		CodeFix_GenerationEventCount:         31,
+		CodeReview_FailedEventCount:          32,
+		Dev_AcceptanceEventCount:             33,
+		Dev_AcceptedLines:                    34,
+		Dev_GeneratedLines:                   35,
+		Dev_GenerationEventCount:             36,
+		DocGeneration_AcceptedFileUpdates:    37,
 		DocGeneration_AcceptedFilesCreations: 38,
-		DocGeneration_AcceptedLineAdditions: 39,
-		DocGeneration_AcceptedLineUpdates: 40,
-		DocGeneration_EventCount: 41,
-		DocGeneration_RejectedFileCreations: 42,
-		DocGeneration_RejectedFileUpdates: 43,
-		DocGeneration_RejectedLineAdditions: 44,
-		DocGeneration_RejectedLineUpdates: 45,
-		TestGeneration_AcceptedLines: 46,
-		TestGeneration_AcceptedTests: 47,
-		TestGeneration_EventCount: 48,
-		TestGeneration_GeneratedLines: 49,
-		TestGeneration_GeneratedTests: 50,
-		Transformation_EventCount: 51,
-		Transformation_LinesGenerated: 52,
-		Transformation_LinesIngested: 53,
+		DocGeneration_AcceptedLineAdditions:  39,
+		DocGeneration_AcceptedLineUpdates:    40,
+		DocGeneration_EventCount:             41,
+		DocGeneration_RejectedFileCreations:  42,
+		DocGeneration_RejectedFileUpdates:    43,
+		DocGeneration_RejectedLineAdditions:  44,
+		DocGeneration_RejectedLineUpdates:    45,
+		TestGeneration_AcceptedLines:         46,
+		TestGeneration_AcceptedTests:         47,
+		TestGeneration_EventCount:            48,
+		TestGeneration_GeneratedLines:        49,
+		TestGeneration_GeneratedTests:        50,
+		Transformation_EventCount:            51,
+		Transformation_LinesGenerated:        52,
+		Transformation_LinesIngested:         53,
 	}
-	
+
 	// Verify that all metrics are accessible
 	// Existing metrics
 	assert.Equal(t, 10, userData.CodeReview_FindingsCount)
@@ -98,7 +98,7 @@ func TestQDevUserDataAllMetrics(t *testing.T) {
 	assert.Equal(t, 22, userData.Inline_AICodeLines)
 	assert.Equal(t, 23, userData.Inline_AcceptanceCount)
 	assert.Equal(t, 24, userData.Inline_SuggestionsCount)
-	
+
 	// New metrics
 	assert.Equal(t, 25, userData.Chat_AICodeLines)
 	assert.Equal(t, 26, userData.Chat_MessagesInteracted)
diff --git a/backend/plugins/q_dev/tasks/s3_data_extractor.go b/backend/plugins/q_dev/tasks/s3_data_extractor.go
index f091e15b9..10ab6a7cd 100644
--- a/backend/plugins/q_dev/tasks/s3_data_extractor.go
+++ b/backend/plugins/q_dev/tasks/s3_data_extractor.go
@@ -119,7 +119,7 @@ func processCSVData(taskCtx plugin.SubTaskContext, db dal.Dal, reader io.ReadClo
 
 	// 读取标头
 	headers, err := csvReader.Read()
-	fmt.Printf("headers: %+v\n", headers)
+	taskCtx.GetLogger().Debug("CSV headers: %+v", headers)
 	if err != nil {
 		return errors.Convert(err)
 	}
@@ -135,7 +135,7 @@ func processCSVData(taskCtx plugin.SubTaskContext, db dal.Dal, reader io.ReadClo
 		}
 
 		// 创建用户数据对象 (updated to include display name resolution)
-		userData, err := createUserDataWithDisplayName(headers, record, fileMeta, data.IdentityClient)
+		userData, err := createUserDataWithDisplayName(taskCtx.GetLogger(), headers, record, fileMeta, data.IdentityClient)
 		if err != nil {
 			return errors.Default.Wrap(err, "failed to create user data")
 		}
@@ -156,7 +156,9 @@ type UserDisplayNameResolver interface {
 }
 
 // 从CSV记录创建用户数据对象 (enhanced with display name resolution)
-func createUserDataWithDisplayName(headers []string, record []string, fileMeta *models.QDevS3FileMeta, identityClient UserDisplayNameResolver) (*models.QDevUserData, errors.Error) {
+func createUserDataWithDisplayName(logger interface {
+	Debug(format string, a ...interface{})
+}, headers []string, record []string, fileMeta *models.QDevS3FileMeta, identityClient UserDisplayNameResolver) (*models.QDevUserData, errors.Error) {
 	userData := &models.QDevUserData{
 		ConnectionId: fileMeta.ConnectionId,
 	}
@@ -165,13 +167,12 @@ func createUserDataWithDisplayName(headers []string, record []string, fileMeta *
 	fieldMap := make(map[string]string)
 	for i, header := range headers {
 		if i < len(record) {
-			// 打印每个header和对应的值,帮助调试
-			fmt.Printf("Mapping header[%d]: '%s' -> '%s'\n", i, header, record[i])
+			logger.Debug("Mapping header[%d]: '%s' -> '%s'", i, header, record[i])
 			fieldMap[header] = record[i]
 			// 同时添加去除空格的版本
 			trimmedHeader := strings.TrimSpace(header)
 			if trimmedHeader != header {
-				fmt.Printf("Also adding trimmed header: '%s'\n", trimmedHeader)
+				logger.Debug("Also adding trimmed header: '%s'", trimmedHeader)
 				fieldMap[trimmedHeader] = record[i]
 			}
 		}
@@ -188,7 +189,7 @@ func createUserDataWithDisplayName(headers []string, record []string, fileMeta *
 	}
 
 	// 设置DisplayName (new functionality)
-	userData.DisplayName = resolveDisplayName(userData.UserId, identityClient)
+	userData.DisplayName = resolveDisplayName(logger, userData.UserId, identityClient)
 
 	// 设置Date
 	dateStr, ok := fieldMap["Date"]
@@ -251,7 +252,9 @@ func createUserDataWithDisplayName(headers []string, record []string, fileMeta *
 }
 
 // resolveDisplayName resolves user ID to display name using Identity Client
-func resolveDisplayName(userId string, identityClient UserDisplayNameResolver) string {
+func resolveDisplayName(logger interface {
+	Debug(format string, a ...interface{})
+}, userId string, identityClient UserDisplayNameResolver) string {
 	// If no identity client available, use userId as fallback
 	if identityClient == nil {
 		return userId
@@ -261,7 +264,7 @@ func resolveDisplayName(userId string, identityClient UserDisplayNameResolver) s
 	displayName, err := identityClient.ResolveUserDisplayName(userId)
 	if err != nil {
 		// Log error but continue with userId as fallback
-		fmt.Printf("Failed to resolve display name for user %s: %v\n", userId, err)
+		logger.Debug("Failed to resolve display name for user %s: %v", userId, err)
 		return userId
 	}
 
diff --git a/backend/plugins/q_dev/tasks/s3_data_extractor_test.go b/backend/plugins/q_dev/tasks/s3_data_extractor_test.go
index 1e84e81ef..fbea299dc 100644
--- a/backend/plugins/q_dev/tasks/s3_data_extractor_test.go
+++ b/backend/plugins/q_dev/tasks/s3_data_extractor_test.go
@@ -40,18 +40,32 @@ func (m *MockIdentityClient) ResolveUserDisplayName(userId string) (string, erro
 // Ensure MockIdentityClient implements UserDisplayNameResolver
 var _ UserDisplayNameResolver = (*MockIdentityClient)(nil)
 
+// MockLogger is a mock implementation of the logger interface for testing
+type MockLogger struct {
+	mock.Mock
+}
+
+func (m *MockLogger) Debug(format string, args ...interface{}) {
+	m.Called(format, args)
+}
+
 func TestCreateUserDataWithDisplayName_Success(t *testing.T) {
 	headers := []string{"UserId", "Date", "CodeReview_FindingsCount", "Inline_AcceptanceCount"}
 	record := []string{"user-123", "2025-06-23", "5", "10"}
 	fileMeta := &models.QDevS3FileMeta{
 		ConnectionId: 1,
 	}
-	
+
 	mockIdentityClient := &MockIdentityClient{}
 	mockIdentityClient.On("ResolveUserDisplayName", "user-123").Return("John Doe", nil)
-	
-	userData, err := createUserDataWithDisplayName(headers, record, fileMeta, mockIdentityClient)
-	
+
+	mockLogger := &MockLogger{}
+	// Add expectations for Debug calls
+	mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'", mock.Anything).Return()
+	mockLogger.On("Debug", "Also adding trimmed header: '%s'", mock.Anything).Return()
+
+	userData, err := createUserDataWithDisplayName(mockLogger, headers, record, fileMeta, mockIdentityClient)
+
 	assert.NoError(t, err)
 	assert.NotNil(t, userData)
 	assert.Equal(t, "user-123", userData.UserId)
@@ -59,7 +73,7 @@ func TestCreateUserDataWithDisplayName_Success(t *testing.T) {
 	assert.Equal(t, uint64(1), userData.ConnectionId)
 	assert.Equal(t, 5, userData.CodeReview_FindingsCount)
 	assert.Equal(t, 10, userData.Inline_AcceptanceCount)
-	
+
 	mockIdentityClient.AssertExpectations(t)
 }
 
@@ -69,17 +83,23 @@ func TestCreateUserDataWithDisplayName_FallbackToUUID(t *testing.T) {
 	fileMeta := &models.QDevS3FileMeta{
 		ConnectionId: 1,
 	}
-	
+
 	mockIdentityClient := &MockIdentityClient{}
 	mockIdentityClient.On("ResolveUserDisplayName", "user-456").Return("user-456", assert.AnError)
-	
-	userData, err := createUserDataWithDisplayName(headers, record, fileMeta, mockIdentityClient)
-	
+
+	mockLogger := &MockLogger{}
+	// Add expectations for Debug calls
+	mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'", mock.Anything).Return()
+	mockLogger.On("Debug", "Also adding trimmed header: '%s'", mock.Anything).Return()
+	mockLogger.On("Debug", "Failed to resolve display name for user %s: %v", mock.Anything).Return()
+
+	userData, err := createUserDataWithDisplayName(mockLogger, headers, record, fileMeta, mockIdentityClient)
+
 	assert.NoError(t, err)
 	assert.NotNil(t, userData)
 	assert.Equal(t, "user-456", userData.UserId)
 	assert.Equal(t, "user-456", userData.DisplayName) // Should fallback to UUID
-	
+
 	mockIdentityClient.AssertExpectations(t)
 }
 
@@ -89,9 +109,14 @@ func TestCreateUserDataWithDisplayName_NoIdentityClient(t *testing.T) {
 	fileMeta := &models.QDevS3FileMeta{
 		ConnectionId: 1,
 	}
-	
-	userData, err := createUserDataWithDisplayName(headers, record, fileMeta, nil)
-	
+
+	mockLogger := &MockLogger{}
+	// Add expectations for Debug calls
+	mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'", mock.Anything).Return()
+	mockLogger.On("Debug", "Also adding trimmed header: '%s'", mock.Anything).Return()
+
+	userData, err := createUserDataWithDisplayName(mockLogger, headers, record, fileMeta, nil)
+
 	assert.NoError(t, err)
 	assert.NotNil(t, userData)
 	assert.Equal(t, "user-789", userData.UserId)
@@ -104,17 +129,22 @@ func TestCreateUserDataWithDisplayName_EmptyDisplayName(t *testing.T) {
 	fileMeta := &models.QDevS3FileMeta{
 		ConnectionId: 1,
 	}
-	
+
 	mockIdentityClient := &MockIdentityClient{}
 	mockIdentityClient.On("ResolveUserDisplayName", "user-empty").Return("", nil)
-	
-	userData, err := createUserDataWithDisplayName(headers, record, fileMeta, mockIdentityClient)
-	
+
+	mockLogger := &MockLogger{}
+	// Add expectations for Debug calls
+	mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'", mock.Anything).Return()
+	mockLogger.On("Debug", "Also adding trimmed header: '%s'", mock.Anything).Return()
+
+	userData, err := createUserDataWithDisplayName(mockLogger, headers, record, fileMeta, mockIdentityClient)
+
 	assert.NoError(t, err)
 	assert.NotNil(t, userData)
 	assert.Equal(t, "user-empty", userData.UserId)
 	assert.Equal(t, "user-empty", userData.DisplayName) // Should fallback when empty
-	
+
 	mockIdentityClient.AssertExpectations(t)
 }
 
@@ -134,24 +164,29 @@ func TestCreateUserDataWithDisplayName_AllExistingMetrics(t *testing.T) {
 	fileMeta := &models.QDevS3FileMeta{
 		ConnectionId: 123,
 	}
-	
+
 	mockIdentityClient := &MockIdentityClient{}
 	mockIdentityClient.On("ResolveUserDisplayName", "test-user").Return("Test User", nil)
-	
-	userData, err := createUserDataWithDisplayName(headers, record, fileMeta, mockIdentityClient)
-	
+
+	mockLogger := &MockLogger{}
+	// Add expectations for Debug calls
+	mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'", mock.Anything).Return()
+	mockLogger.On("Debug", "Also adding trimmed header: '%s'", mock.Anything).Return()
+
+	userData, err := createUserDataWithDisplayName(mockLogger, headers, record, fileMeta, mockIdentityClient)
+
 	assert.NoError(t, err)
 	assert.NotNil(t, userData)
-	
+
 	// Verify basic fields
 	assert.Equal(t, "test-user", userData.UserId)
 	assert.Equal(t, "Test User", userData.DisplayName)
 	assert.Equal(t, uint64(123), userData.ConnectionId)
-	
+
 	// Verify date parsing
 	expectedDate, _ := time.Parse("2006-01-02", "2025-06-23")
 	assert.Equal(t, expectedDate, userData.Date)
-	
+
 	// Verify all existing metric fields
 	assert.Equal(t, 1, userData.CodeReview_FindingsCount)
 	assert.Equal(t, 2, userData.CodeReview_SucceededEventCount)
@@ -168,7 +203,7 @@ func TestCreateUserDataWithDisplayName_AllExistingMetrics(t *testing.T) {
 	assert.Equal(t, 13, userData.Inline_AICodeLines)
 	assert.Equal(t, 14, userData.Inline_AcceptanceCount)
 	assert.Equal(t, 15, userData.Inline_SuggestionsCount)
-	
+
 	mockIdentityClient.AssertExpectations(t)
 }
 
@@ -186,30 +221,35 @@ func TestCreateUserDataWithDisplayName_AllNewMetrics(t *testing.T) {
 		"TestGeneration_GeneratedLines", "TestGeneration_GeneratedTests",
 		"Transformation_EventCount", "Transformation_LinesGenerated", "Transformation_LinesIngested",
 	}
-	
+
 	record := []string{
 		"test-user", "2025-06-23",
 		"101", "102", "103", "104", "105", "106", "107", "108", "109", "110",
 		"111", "112", "113", "114", "115", "116", "117", "118", "119", "120",
 		"121", "122", "123", "124", "125", "126", "127", "128", "129",
 	}
-	
+
 	fileMeta := &models.QDevS3FileMeta{
 		ConnectionId: 123,
 	}
-	
+
 	mockIdentityClient := &MockIdentityClient{}
 	mockIdentityClient.On("ResolveUserDisplayName", "test-user").Return("Test User", nil)
-	
-	userData, err := createUserDataWithDisplayName(headers, record, fileMeta, mockIdentityClient)
-	
+
+	mockLogger := &MockLogger{}
+	// Add expectations for Debug calls
+	mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'", mock.Anything).Return()
+	mockLogger.On("Debug", "Also adding trimmed header: '%s'", mock.Anything).Return()
+
+	userData, err := createUserDataWithDisplayName(mockLogger, headers, record, fileMeta, mockIdentityClient)
+
 	assert.NoError(t, err)
 	assert.NotNil(t, userData)
-	
+
 	// Verify basic fields
 	assert.Equal(t, "test-user", userData.UserId)
 	assert.Equal(t, "Test User", userData.DisplayName)
-	
+
 	// Verify all new metric fields
 	assert.Equal(t, 101, userData.Chat_AICodeLines)
 	assert.Equal(t, 102, userData.Chat_MessagesInteracted)
@@ -240,7 +280,7 @@ func TestCreateUserDataWithDisplayName_AllNewMetrics(t *testing.T) {
 	assert.Equal(t, 127, userData.Transformation_EventCount)
 	assert.Equal(t, 128, userData.Transformation_LinesGenerated)
 	assert.Equal(t, 129, userData.Transformation_LinesIngested)
-	
+
 	mockIdentityClient.AssertExpectations(t)
 }
 
@@ -248,60 +288,70 @@ func TestCreateUserDataWithDisplayName_MissingMetrics(t *testing.T) {
 	// Only provide a few metrics in the CSV
 	headers := []string{"UserId", "Date", "CodeReview_FindingsCount", "Chat_AICodeLines"}
 	record := []string{"test-user", "2025-06-23", "42", "99"}
-	
+
 	fileMeta := &models.QDevS3FileMeta{
 		ConnectionId: 123,
 	}
-	
+
 	mockIdentityClient := &MockIdentityClient{}
 	mockIdentityClient.On("ResolveUserDisplayName", "test-user").Return("Test User", nil)
-	
-	userData, err := createUserDataWithDisplayName(headers, record, fileMeta, mockIdentityClient)
-	
+
+	mockLogger := &MockLogger{}
+	// Add expectations for Debug calls
+	mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'", mock.Anything).Return()
+	mockLogger.On("Debug", "Also adding trimmed header: '%s'", mock.Anything).Return()
+
+	userData, err := createUserDataWithDisplayName(mockLogger, headers, record, fileMeta, mockIdentityClient)
+
 	assert.NoError(t, err)
 	assert.NotNil(t, userData)
-	
+
 	// Verify provided metrics are set correctly
 	assert.Equal(t, 42, userData.CodeReview_FindingsCount)
 	assert.Equal(t, 99, userData.Chat_AICodeLines)
-	
+
 	// Verify missing metrics are set to 0
 	assert.Equal(t, 0, userData.CodeReview_SucceededEventCount)
 	assert.Equal(t, 0, userData.InlineChat_AcceptanceEventCount)
 	assert.Equal(t, 0, userData.Chat_MessagesInteracted)
 	assert.Equal(t, 0, userData.TestGeneration_AcceptedTests)
 	assert.Equal(t, 0, userData.Transformation_LinesIngested)
-	
+
 	mockIdentityClient.AssertExpectations(t)
 }
 
 func TestCreateUserDataWithDisplayName_InvalidMetricValues(t *testing.T) {
 	headers := []string{
-		"UserId", "Date", "CodeReview_FindingsCount", "Chat_AICodeLines", 
+		"UserId", "Date", "CodeReview_FindingsCount", "Chat_AICodeLines",
 		"InlineChat_AcceptanceEventCount", "TestGeneration_AcceptedTests",
 	}
 	record := []string{"test-user", "2025-06-23", "42", "not-a-number", "abc", ""}
-	
+
 	fileMeta := &models.QDevS3FileMeta{
 		ConnectionId: 123,
 	}
-	
+
 	mockIdentityClient := &MockIdentityClient{}
 	mockIdentityClient.On("ResolveUserDisplayName", "test-user").Return("Test User", nil)
-	
-	userData, err := createUserDataWithDisplayName(headers, record, fileMeta, mockIdentityClient)
-	
+
+	mockLogger := &MockLogger{}
+	// Add expectations for Debug calls
+	mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'", mock.Anything).Return()
+	mockLogger.On("Debug", "Also adding trimmed header: '%s'", mock.Anything).Return()
+
+	userData, err := createUserDataWithDisplayName(mockLogger, headers, record, fileMeta, mockIdentityClient)
+
 	assert.NoError(t, err)
 	assert.NotNil(t, userData)
-	
+
 	// Verify valid metric is set correctly
 	assert.Equal(t, 42, userData.CodeReview_FindingsCount)
-	
+
 	// Verify invalid metrics are set to 0
 	assert.Equal(t, 0, userData.Chat_AICodeLines)
 	assert.Equal(t, 0, userData.InlineChat_AcceptanceEventCount)
 	assert.Equal(t, 0, userData.TestGeneration_AcceptedTests)
-	
+
 	mockIdentityClient.AssertExpectations(t)
 }
 
@@ -311,9 +361,14 @@ func TestCreateUserDataWithDisplayName_MissingUserId(t *testing.T) {
 	fileMeta := &models.QDevS3FileMeta{
 		ConnectionId: 1,
 	}
-	
-	userData, err := createUserDataWithDisplayName(headers, record, fileMeta, nil)
-	
+
+	mockLogger := &MockLogger{}
+	// Add expectations for Debug calls
+	mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'", mock.Anything).Return()
+	mockLogger.On("Debug", "Also adding trimmed header: '%s'", mock.Anything).Return()
+
+	userData, err := createUserDataWithDisplayName(mockLogger, headers, record, fileMeta, nil)
+
 	assert.Error(t, err)
 	assert.Nil(t, userData)
 	assert.Contains(t, err.Error(), "UserId not found")
@@ -325,9 +380,14 @@ func TestCreateUserDataWithDisplayName_MissingDate(t *testing.T) {
 	fileMeta := &models.QDevS3FileMeta{
 		ConnectionId: 1,
 	}
-	
-	userData, err := createUserDataWithDisplayName(headers, record, fileMeta, nil)
-	
+
+	mockLogger := &MockLogger{}
+	// Add expectations for Debug calls
+	mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'", mock.Anything).Return()
+	mockLogger.On("Debug", "Also adding trimmed header: '%s'", mock.Anything).Return()
+
+	userData, err := createUserDataWithDisplayName(mockLogger, headers, record, fileMeta, nil)
+
 	assert.Error(t, err)
 	assert.Nil(t, userData)
 	assert.Contains(t, err.Error(), "Date not found")
@@ -346,10 +406,10 @@ func TestParseDate(t *testing.T) {
 		{"2025-07-10T15:04:05Z", time.Date(2025, 7, 10, 15, 4, 5, 0, time.UTC), false},
 		{"invalid-date", time.Time{}, true},
 	}
-	
+
 	for _, tc := range testCases {
 		date, err := parseDate(tc.dateStr)
-		
+
 		if tc.expectError {
 			assert.Error(t, err)
 		} else {
@@ -361,13 +421,13 @@ func TestParseDate(t *testing.T) {
 
 func TestParseInt(t *testing.T) {
 	fieldMap := map[string]string{
-		"ValidInt": "42",
-		"ZeroInt": "0",
+		"ValidInt":    "42",
+		"ZeroInt":     "0",
 		"NegativeInt": "-10",
-		"InvalidInt": "not-a-number",
+		"InvalidInt":  "not-a-number",
 		"EmptyString": "",
 	}
-	
+
 	assert.Equal(t, 42, parseInt(fieldMap, "ValidInt"))
 	assert.Equal(t, 0, parseInt(fieldMap, "ZeroInt"))
 	assert.Equal(t, -10, parseInt(fieldMap, "NegativeInt"))