ã¯ããã«
CloudPlatformé¨ã®pddgã§ããGoã«ãããOpenTelemetryã®è¨è£
ã©ã¤ãã©ãªãç¹ã«database/sqlããã±ã¼ã¸ã®ãã¬ã¼ã·ã³ã°ãè¡ãããã®ã©ã¤ãã©ãªã«ã¯ããã¡ã¯ãã¹ã¿ã³ãã¼ãã¨å¼ã¹ããã®ãããã¾ãããæ¬è¨äºã§ã¯ãããã¤ãã®ãµã¼ããã¼ãã£ã¼ã©ã¤ãã©ãªã®æ©è½ãæ¯è¼ãã¾ã¨ãã¾ãããæ¡ç¨ããã©ã¤ãã©ãªã¯å®éã«æ¬çªç°å¢ã®ãµã¼ãã¹ã®è¨è£
ã«å©ç¨ãã¦ãã¾ãã
ãã®å
容ã¯ã2025å¹´ã«éå¬ããããµãã¼ã¤ã³ã¿ã¼ã³ã·ããã«ããã¦ããã©ãããã©ã¼ã ï¼èªç¤¾åºç¤ï¼ã³ã¼ã¹ã«åå ãã¦é ããæ³ç°ããã«ãæä¼ãé ãã¦ã¾ã¨ãããã®ã§ãã
å®éã«æ¡ç¨ããã©ã¤ãã©ãªãç¨ããã¨ãããããªã³ã¼ã追å ã§ä»¥ä¸ã®æ§ãªãã¬ã¼ã¹ãåå¾ã§ããããã«ãªãã¾ããæ¨ªæ£ãåã¹ãããã«ããã£ãæéã表ããåã¹ããããã¨ã«ãã®å¼æ°ãã¡ã¿ãã¼ã¿ã表示ã§ãã¾ããé害çºçæãªã©ã«ã¯ãããã®æ å ±ãæ´»ç¨ãã¦ã¢ããªã±ã¼ã·ã§ã³ã®å é¨ã§å®éã«çºçãã¦ããç¶æ³ããããã°ã§ããããã«ãªãã¾ãã

èæ¯
ãµã¤ãã¦ãºã§ã¯ã夿°ã®ã¢ããªã±ã¼ã·ã§ã³ã»ããã«ã¦ã§ã¢ãKubernetesãã¼ã¹ã®ã¤ã³ãã©åºç¤ä¸ã§åä½ãã¦ãã¾ããè¤æ°ã®ãã¤ã¯ããµã¼ãã¹ãä»ã®ãã¤ã¯ããµã¼ãã¹ããã¼ã¿ãã¼ã¹ãå¼ã³åºãã¦ãããåé¡ãçºçããéã«ã©ã®ãµã¼ãã¹ã®ä½ãåå ãªã®ããç¹å®ãããã¨ã¯å®¹æã§ã¯ããã¾ããããã®ãããªåé¡ã®ç¹å®ã«å½¹ç«ã¦ãããããµã¼ãã¹éã®å¼ã³åºãã追跡ãã¦å¯è¦åãã忣ãã¬ã¼ã·ã³ã°æè¡ãä¸è¬çã«å°å ¥ãããããã«ãªã£ã¦ãã¾ããããµã¤ãã¦ãºã§ãOpenTelemetryãç¨ãã忣ãã¬ã¼ã·ã³ã°ã®å°å ¥ã«åãçµãã§ãã*1ãæã ã®ãã¼ã ã§ã¯ä¸»ã«Goè¨èªã§æ¸ãããã¢ããªã±ã¼ã·ã§ã³ã¸ã®è¨è£ ãè¡ã£ã¦ãã¾ãã
ä»è¨èªã®OpenTelemetry SDKã«ã¯èªåè¨è£ ã¨ããã¢ããªã±ã¼ã·ã§ã³ã³ã¼ãã夿´ããã«è¨æ¸¬ãè¡ãä»çµã¿ãæä¾ããã¦ãããã®ãããã¾ãããGoè¨èªã®OpenTelemetry SDKã«ã¯èªåè¨è£ ã®ä»çµã¿ãããã¾ãã*2ããã®ãããã¢ããªã±ã¼ã·ã§ã³ã³ã¼ãã«ããã¦æç¤ºçã«è¨æ¸¬ã³ã¼ãã追å ããå¿ è¦ãããã¾ã*3ã
net/httpãgRPCãªã©ã®ä¸»è¦ãªæ©è½ã«ã¯è¨è£
ã©ã¤ãã©ãªãæä¾ããã¦ãã*4ãæ¯è¼ç容æã«è¨è£
ã§ãã¾ããããããGoè¨èªã®æ¨æºã©ã¤ãã©ãªã§ããdatabase/sqlã«å¯¾ããã¢ã¸ã¥ã¼ã«ã¯æä¾ããã¦ãããããµã¼ããã¼ãã£è£½ã®è¨è£
ã©ã¤ãã©ãªã®å©ç¨ãæ¤è¨ãã¦ãã¾ãããä»åã®ã¤ã³ã¿ã¼ã³ã·ããã§ã¯ãããã¾ã§å¾åãã«ãã¦ãã¾ã£ã¦ãããµã¼ãã¹ã«ããã忣ãã¬ã¼ã·ã³ã°ã®å°å
¥ããã³è¨è£
ã©ã¤ãã©ãªã®é¸å®ã«åãçµãã§ããã ãã¾ããã
ãµã³ãã«ã³ã¼ãã®å®è£
æã
ã®ä¸»ãªã¦ã¼ã¹ã±ã¼ã¹ã¨ãã¦ã¯ãdatabase/sqlã¨github.com/jmoiron/sqlxãå©ç¨ããMySQLã«ã¢ã¯ã»ã¹ããã¢ããªã±ã¼ã·ã§ã³ãã»ã¨ãã©ã§ãã
ã¾ãã*sql.DB.ExecContextã*sql.DB.QueryContextãªã©ã¯å©ç¨ãããã»ã¨ãã©ã®å ´åã§ãã©ã³ã¶ã¯ã·ã§ã³ãå©ç¨ãã¦ãããã¨ãããã®é¨åã«ãã©ã¼ã«ã¹ãçµã£ã¦ãã¾ãã
ãµã³ãã«ã³ã¼ãã¨ãã¦ç°¡åãªTODOã¢ããªã®APIãå®è£
ãã¾ããããªãã¸ããªã¯ä»¥ä¸ã«ããã¾ãã
ãã®ã³ã¼ãã«å¯¾ãã¦ãåã©ã¤ãã©ãªãç¨ãã¦è¨è£ ãè¡ãã³ã¼ããä¾ç¤ºãã¾ãã
å®éã®ã¤ã³ã¿ã¼ã³ã·ããã§ã¯æã ã®å é¨ãµã¼ãã¹ã®ã³ã¼ããç¨ãã¦è¨è£ ãè¡ã£ã¦ããã£ã¦ããããã®éã®ã³ã¼ããã¹ã¯ãªã¼ã³ã·ã§ãããããã®ã§ãããå ¬éã«å½ãã£ã¦ã¡ã³ã¿ã¼å´ã§ãµã³ãã«ã³ã¼ãã«å·®ãæ¿ãããã¦é ãã¦ãã¾ãããäºæ¿ãã ããã
æ¯è¼ããã©ã¤ãã©ãª
ä»åã¯åè£ã¨ãã¦ããã¤ãã®ã©ã¤ãã©ãªãããã¯ã¢ããããå®éã«ãã¼ã«ã«ã§ã®è¨è£ ãè¡ã£ã¦ããã ãã¾ããã
æ¬è¨äºã§ã¯ããã¾ã§æã ã®ç¾å¨ã®ãã¼ãºãæºãããã忣ãã¬ã¼ã·ã³ã°ã«ãã©ã¼ã«ã¹ããæ¯è¼ãè¡ã£ã¦ãã¾ãããããã®ã©ã¤ãã©ãªã«ã¯OpenTelemetryã®ã¡ããªã¯ã¹åéã«é¢ããæ©è½ãå«ã¾ãã¦ãã¾ãããè©³ç´°ãªæ¯è¼ã¯è¡ã£ã¦ãã¾ããã
1. github.com/uptrace/opentelemetry-go-extra/otelsql
uptraceã¯OpenTelemetryãæ´»ç¨ãããªãã¶ã¼ãããªãã£ãã©ãããã©ã¼ã ã®åç¨ãµã¼ãã¹ãæä¾ãã¦ãã伿¥ã§ãã https://uptrace.dev/
ãã®ã¢ã¸ã¥ã¼ã«ã¯uptraceãOSSã¨ãã¦å ¬éãã¦æä¾ãã¦ãããã®ã§ãããã¥ã¡ã³ãã§ãç´¹ä»ããã¦ãã¾ãã
2025/9æç¹ã§Staræ°ã¯ãã®ä¸ã§ã¯2çªç®ã«å¤ãã351ã§ãããã¡ã³ããã³ã¹èªä½ã¯é »ç¹ã«è¡ããã¦ããããã§ã¯ãªãããã§ãuptrace/opentelemetry-go-extraèªä½ã®æçµã³ãããã2024å¹´11æã§ãããã¨ã¯ããæ°ã«ãªãç¹ã§ãã
è¨è£ æ¹æ³
db, err := otelsql.Open("mysql", dsn, otelsql.WithAttributes(semconv.DBSystemNameMySQL), otelsql.WithDBName("todoapp"), ) if err != nil { return fmt.Errorf("failed to open database: %w", err) } defer db.Close() todoService := NewTodoService(sqlx.NewDb(db, "mysql"))
github.com/uptrace/opentelemetry-go-extra/otelsqlx ã¨ããã¢ã¸ã¥ã¼ã«ãåå¨ãã¾ããããã¯ä¸è¨ã®ãããªotelsql.Openãã¦sqlx.NewDbã§ã©ããããå®è£
ãæä¾ãã¦ããã ãã§ãã
åå¾ã§ããæ å ±

- db.Connect
- db.Ping
- db.Begin
- db.Query
- db.Exec
- db.Prepare
- stmt.Exec
- stmt.Query
- tx.Commit
- tx.Rollback
ãªã©ã®æä½ã«å¯¾ãã¦spanã使ããã¾ããã»ã¨ãã©æè»æ§ã¯ãªãã夿´å¯è½ãªã®ã¯spanã¸ã®å±æ§ã®è¿½å ãªã©ä¸é¨ã®ãã®ã«éããã¾ãã
å®è¡ãããstatement㯠db.statement ã¨ãã¦Spanã«è¿½å ããã¾ããPrepareãããstatementã®å ´åãåæ§ã§ãããï¼é©åã«ãã¬ã¼ã¹ãã«ããå©ç¨ãã¦ããã°ï¼å
¥åããããã©ã¡ã¼ã¿ãæå³ããSpanã«å«ã¾ãããã¨ã¯ããã¾ããã
åå¾å¯è½ãªå ´åã«ã¯rows_affected ãåå¾ãã¦ããã®ãç¹å¾´çã§ããã
ã¯ã¨ãªã®ãã©ã¡ã¼ã¿ãSpanã«è¿½å ããæ©è½ã¯æ¢ããéãã§ã¯è¦ã¤ããã¾ããã§ãããå¿ è¦ã§ããã°èªèº«ã§spanã«è¿½å ããå¿ è¦ãããã¾ãã
2. github.com/XSAM/otelsql
ãã®å®è£ ã¯å ã opentelemetry-go-contribã«è²¢ç®ããããã¨ãã¦ãããã®ããçµæçã«åãè¾¼ã¾ããç¬èªã«ãã¹ãããããã®ã§ãã
https://github.com/XSAM/otelsql?tab=readme-ov-file#why-port-this
Based on this comment, OpenTelemetry SIG team like to see broader usage and community consensus on an approach before they commit to the level of support that would be required of a package in contrib. But it is painful for users without a stable version, and they have to use replacement in go.mod to use this instrumentation.
2025/9æç¹ã§Staræ°ã¯ãã®ä¸ã§ã¯æãå¤ã356ã§ãããç¾å¨ãXSAMãããã¡ã³ããã³ã¹ãç¶ãããã¦ãã¾ãã
è¨è£ æ¹æ³
otelsqlã使ã£ã¦ç¹å®ã®driverã§ãã¼ã¿ãã¼ã¹ãOpenãã¾ããotelsql.WithAttributes ã§Spanã«è¿½å ã§ä»ä¸ãã屿§ãæå®ã§ãã¾ãã以ä¸ã®ä¾ã§ã¯DBSystemãMySQLã«è¨å®ãã¦ãã¾ãã
db, err := otelsql.Open("mysql", dsn, otelsql.WithAttributes(semconv.DBSystemNameMySQL), ) if err != nil { return fmt.Errorf("failed to open database: %w", err) } defer db.Close() todoService := NewTodoService(sqlx.NewDb(db, "mysql"))
åå¾ã§ããæ å ±

å¤ãã®ã¹ãããã«å¯¾ãã¦spanã使ããã¾ãã
- sql.connector.connect
- sql.conn.reset_session
- sql.conn.exec
- sql.conn.query
- sql.conn.prepare
- sql.conn.begin_tx
- sql.conn.commit
- sql.conn.rollback
- sql.stmt.exec
- sql.stmt.query
- sql.rows
ã¾ããéä¿¡ããspanãããç´°ãããªãã·ã§ã³ã§å¶å¾¡ã§ããããã«ãªã£ã¦ãã¾ãã詳ãã㯠otelsql.SpanOptions ãåç
§ããã¨è¯ãã§ãããã
https://github.com/XSAM/otelsql/blob/7ca825674bad2598e7e78b502986d3ed27ca0337/config.go#L107-L151
ããã©ã«ãã§ã¯ä»¥ä¸ã®spanã¯æå¹ã«ãªã£ã¦ãã¾ããã
- sql.conn.ping
- sql.rows.next
ç¹ã«Rows.Nextã¯å¤§éã®ãã¼ã¿ãæ±ãå ´åã«spanã大éã«ä½æããã¦ãã¾ããããæå¹åã¯æ éã«æ¤è¨ããå¿ è¦ãããã¾ãã
å®è¡ãããstatement㯠db.statement ã¨ãã¦Spanã«è¿½å ããã¾ã*5ãPrepareãããstatementã®å ´åãåæ§ã§ãããï¼é©åã«ãã¬ã¼ã¹ãã«ããå©ç¨ãã¦ããã°ï¼å
¥åããããã©ã¡ã¼ã¿ãæå³ããSpanã«å«ã¾ãããã¨ã¯ããã¾ããã
ã¯ã¨ãªã«å ãã¦ãã©ã¡ã¼ã¿ãåå¾ãããå ´åã¯èªèº«ã§spanã«è¿½å ããããã® AttributeGetter ãå®è£
ããå¿
è¦ãããã¾ãã
https://pkg.go.dev/github.com/XSAM/otelsql#AttributesGetter
func attributeGetter(ctx context.Context, method otelsql.Method, query string, args []driver.NamedValue) []attribute.KeyValue { if len(args) == 0 { return nil } attrs := make([]attribute.KeyValue, len(args)) for i, arg := range args { argName := arg.Name if argName == "" { argName = strconv.Itoa(arg.Ordinal) } attrs[i] = semconv.DBQueryParameter(argName, fmt.Sprintf("%v", arg.Value)) } return attrs }
db, err := otelsql.Open("mysql", dsn,
otelsql.WithAttributesGetter(attributeGetter),
)

driver.NamedValue ã® Name ãã£ã¼ã«ãã¯ååä»ããã©ã¡ã¼ã¿ï¼sql.Namedï¼ãå©ç¨ãã¦ããå ´åã«ãã®ååãå
¥ãã¾ãããã㯠jmoiron/sqlxã® Named* ç³»ã®ã¡ã½ããããµãã¼ãããæ©è½ã¨ã¯ç°ãªããã®ã§ãããã¨ã«æ³¨æãã¦ãã ããã
MySQLã§ã¯ååä»ããã©ã¡ã¼ã¿ã¯ãµãã¼ãããã¦ããªã*6ãããsql.Named ã使ãã¨ã¨ã©ã¼ãçºçãã¾ãããã®ãããdriver.NamedValue.Name ã使ã£ã¦ç¹å®ã®ååã®ãã©ã¡ã¼ã¿ï¼ä¾ãã° password ï¼ã ãã¯å¤ããã¹ã¯ãããã¨ãã£ãå®è£
ã¯ã§ãã¾ããã
注æç¹
go-sql-driver/mysql ã¯å
é¨ã§ driver.ErrSkip ãå©ç¨ãããã¨ãããã®ã§ãããgithub.com/XSAM/otelsql ã¯ãããã¨ã©ã¼ã¨ãã¦Spanã«è¨é²ãã¦ãã¾ãã¾ããæ£å¸¸ãªæåã®ä¸ã§å¼ã³åºããããã¨ã©ã¼ã§ããããããããã¨ã©ã¼ã¨ãã¦è¨é²ããã¨çã«éè¦ãªã¨ã©ã¼ãè¦éãã¦ãã¾ãå¯è½æ§ãããã¾ãã

otelsql.SpanOptions.DisableErrSkip ã true ã«è¨å®ãããã¨ã§ãã®æåãç¡å¹åã§ãã¾ãã
ä»ã®DBMSãã©ã¤ãã§ãåæ§ã®åé¡ãããããããã¾ããã
db, err := otelsql.Open("mysql", dsn, otelsql.WithAttributes(semconv.DBSystemNameMySQL), otelsql.WithSpanOptions(otelsql.SpanOptions{ DisableErrSkip: true, }), )
3. go.nhat.io/otelsql
ãªãã¸ããªã¯ä»¥ä¸ã«ããã¾ãã
ä»åæ¤è¨ã«ä¸ãããã®ã®ä¸ã§ã¯æãStaræ°ãå°ãªãã2025/9æç¹ã§119ã§ãããdependabotã«ããæ´æ°ä»¥å¤ã®ã³ãããã¯2025/4ã«è¡ããã¦ãã¾ããç©æ¥µçã«æ©è½éçºãè¡ããã¦ããããã§ã¯ãªãããã§ãã
è¨è£ æ¹æ³
ãã®ã©ã¤ãã©ãªã¯ otelsql.Register ã使ã£ã¦æ°ãããã©ã¤ãåãç»é²ãããã®ãã©ã¤ãåã使ã£ã¦ sql.Open ãã¾ãã
driverName, err := otelsql.Register("mysql", otelsql.WithSystem(semconv.DBSystemNameMySQL), ) if err != nil { return fmt.Errorf("failed to register otelsql driver: %w", err) } db, err := sql.Open(driverName, dsn) if err != nil { return fmt.Errorf("failed to open database: %w", err) } defer db.Close() todoService := NewTodoService(sqlx.NewDb(db, "mysql"))
sqlxã使ãå ´åã sqlx.Open ã使ã£ã¦ã¯ãªããªãã¨æ¸ããã¦ãã¾ããããã¯sqlxããã©ã¤ãåãå
ã« Named* ç³»ã®ã¡ã½ããã§ä½¿ããã¬ã¼ã¹ãã«ããæ±ºå®ãããããå©ç¨ãããã¼ã¿ãã¼ã¹ã¨ç°ãªããã©ã¤ãåãæå®ããã¨ãã«æ£ããåä½ããªããã¨ãããããã§ã((github.com/XSAM/otelsqlã«ãdriverãRegisterãã颿°ããããããã使ãå ´åã¯åæ§ã®åé¡ãè¸ãã±ã¼ã¹ãããã¾ãã)ã
https://github.com/nhatthm/otelsql?tab=readme-ov-file#jmoironsqlx
Do not use the
sqlx.Openandsqlx.Connectmethods.jmoiron/sqlxuses the driver name to figure out which database is being used. It uses this knowledge to convert named queries to the correct bind type (dollar sign, question mark) if named queries are not supported natively by the database.
åå¾ã§ããæ å ±

ããã©ã«ãã§ã¯ä»¥ä¸ã®spanã使ããã¾ãã
- sql:begin_transaction
- sql:exec
- sql:query
- sql:prepare
- sql:commit
- sql:rollback
以ä¸ã®spanã¯ãªãã·ã§ã³ã§æå¹åã§ãã¾ãã
- sql:last_insert_id
- sql:rows_affected
- sql:ping
- sql:rows_close
- sql:rows_next
ã¾ããã¯ã¨ãªããã©ã¡ã¼ã¿ãSpanã«è¿½å ãããã©ããããªãã·ã§ã³ã§å¶å¾¡ã§ãã¾ãã
otelsql.WithQueryWithArgs()- ã¯ã¨ãªã¨ãã©ã¡ã¼ã¿ãSpanã«è¿½å ãã
otelsql.WithQueryWithoutArgs()- ã¯ã¨ãªã®ã¿ãSpanã«è¿½å
otelsql.WithQuery(func(ctx context.Context, query string, args []driver.NamedValue) []attribute.KeyValue)- ã¯ã¨ãªã¨ãã©ã¡ã¼ã¿ãSpanã«è¿½å ããããã®é¢æ°ãæå®ãã
以ä¸ã¯ WithQuery ã使ã£ã¦ otelsql.WithQueryWithArgs() ã«è¿ãæåãå®è£
ããä¾ã§ãã
func traceQuery(ctx context.Context, query string, args []driver.NamedValue) []attribute.KeyValue { attrs := make([]attribute.KeyValue, 0, len(args)+1) attrs = append(attrs, semconv.DBQueryText(query)) for _, arg := range args { argName := arg.Name if argName == "" { argName = strconv.Itoa(arg.Ordinal) } attrs = append(attrs, semconv.DBQueryParameter(argName, fmt.Sprintf("%v", arg.Value))) } return attrs }
driverName, err := otelsql.Register("mysql",
otelsql.WithSystem(semconv.DBSystemNameMySQL),
otelsql.WithQuery(traceQuery),
)

注æç¹
github.com/XSAM/otelsql ã¨åæ§ã«ãMySQLãã©ã¤ãã® driver.ErrSkip ãã¨ã©ã¼ã¨ãã¦Spanã«è¨é²ãã¦ãã¾ãã¾ãã以ä¸ã®æ§ã«ãªãã·ã§ã³ãè¨å®ãããã¨ã§ãã®æåãç¡å¹åã§ãã¾ãã
driverName, err := otelsql.Register("mysql",
otelsql.WithSystem(semconv.DBSystemNameMySQL),
otelsql.DisableErrSkip(),
)
ã©ããé¸ã¶ã¹ãã
æ§ã ãªè¦³ç¹ããæ¯è¼ãã¦ã¿ã¾ããããããã¤ãã®è¦³ç¹ããä»å㯠github.com/XSAM/otelsql ãæ¡ç¨ãããã¨ã«ãã¾ãããå®éã«æ¬çªç°å¢ã®ãµã¼ãã¹ã®è¨è£ ã«å©ç¨ãã¦ãã¾ãã
- åå¾ã§ããæ å ±ãè±å¯ã§ãããspanã®ç²åº¦ãç´°ããå¶å¾¡ã§ãã
- ç¾å¨ãã¡ã³ããã³ã¹ãç¶ãããã¦ãã
- å¿ è¦ã§ããã°ã¯ã¨ãªãã©ã¡ã¼ã¿ãSpanã«è¿½å ã§ãã
OTEL_SEMCONV_STABILITY_OPT_INç°å¢å¤æ°ã«å¯¾å¿ãã¦ãã*7ã
ãã¼ã ã«ãã£ã¦è¦ä»¶ã¯ç°ãªãã¨æãã¾ãããä¹ãæããé常ã«é«ã³ã¹ããªã©ã¤ãã©ãªã§ãç¡ãã¨æãã®ã§ãæ°ã«å ¥ã£ããã®æ¡ç¨ãã¦ã¿ã¦ãè¯ãã®ã§ã¯ãªããã¨æãã¾ããã
ã¯ã¨ãªãã©ã¡ã¼ã¿ãSpanã«è¿½å ããå ´åã®æ³¨æç¹
æ©è½ã¨ãã¦å®ç¾ã¯å¯è½ãªãã®ã®ãã©ã®ãããªã±ã¼ã¹ã§ãæå¹åãã¦ãããã®ã§ã¯ãªãã¨èãã¦ãã¾ãã以ä¸ã«æ³¨æç¹ãæãã¾ãã
ãã©ã¡ã¼ã¿ã®ãã¹ãã³ã°ã鏿çãã¬ã¼ã·ã³ã°
ã¯ã¨ãªãã©ã¡ã¼ã¿ãSpanã«è¿½å ããå ´åããã¹ã¯ã¼ããªã©ã®æ©å¯æ
å ±ãå«ã¾ããå¯è½æ§ããããã¨ã«æ³¨æãå¿
è¦ã§ãããããé²ãããã«ã¯ã AttributeGetter ã¨ãã¦æ¸¡ã颿°ã®ä¸ã§ãã©ã¡ã¼ã¿ã鏿çã«è¿½å ãããããã¹ãã³ã°ãããããå¿
è¦ãããã¾ãã
ãããåè¿°ããããã«ãGoã®MySQLãã©ã¤ãã¯ååã¤ããã©ã¡ã¼ã¿ããµãã¼ããã¦ãã¾ãããã¯ã¨ãªæ¬ä½ãè§£æãããããªãããããã©ã®ãã©ã¡ã¼ã¿ãæ©å¯æ å ±ã§ããããç¹å®ãããã¨ã¯å°é£ã§ãããã£ã¦ããã®ã¾ã¾ä½¿ãéããã©ã¡ã¼ã¿ãSpanã«è¿½å ããå ´åã¯å ¨ã¦ã®ãã©ã¡ã¼ã¿ã追å ããããå ¨ã追å ããªããã®ã©ã¡ããã鏿ãããã¨ã«ãªãã§ãããã
AttributeGetter ã context.Context ãåãåããã¨ãããä½ããã®ãã¬ã¼ã¹ã«é¢ãããã³ããå«ãã¦ã¯ã¨ãªå®è¡ãããã¨ã§ãã©ã¡ã¼ã¿ã®ã¹ãã³ã¸ã®è¿½å ã忍鏿ã§ããããã«ãããã¨èãã¦ã¯ãã¾ãããã¾ã è¯ãã¤ã³ã¿ã¼ãã§ã¼ã¹ã¯æãã¤ãã¦ãã¾ããã
sqlxã® Named* ã§è¤æ°è¡ã®INSERTãããå ´å
sqlx ã® NamedExec ã¯è¤æ°è¡ã®INSERTããµãã¼ããã¦ãã¾ããä¾ãã°ä»¥ä¸ã®ãããªã³ã¼ãã§ãã
todoMaps := make([]map[string]any, len(todos)) for i, todo := range todos { todoMaps[i] = map[string]any{ "title": todo.Title, "description": todo.Description, } } query := `INSERT INTO todos (title, description, created_at) VALUES (:title, :description, NOW())` result, err := tx.NamedExecContext(ctx, query, todoMaps) if err != nil { return 0, fmt.Errorf("failed to insert todos: %w", err) }
ãã®å ´åã todoMaps ã®è¦ç´ æ°ã«å¿ã㦠? ãã¬ã¼ã¹ãã«ããå±éããããã©ã¡ã¼ã¿ãè¨å®ããã¾ããä¾ãã° todoMaps ã3ä»¶ã®ãã¼ã¿ãæã£ã¦ããã°ã query ã¯ä»¥ä¸ã®ããã«ãªãã¾ãã
INSERT INTO todos (title, description, created_at) VALUES (?, ?, NOW()), (?, ?, NOW()), (?, ?, NOW())
æ¬è¨äºã§ç´¹ä»ããã¯ã¨ãªãã©ã¡ã¼ã¿ãSpanã«è¿½å ããæ¹æ³ã使ãã¨ã db.statement ã«ä¸è¨ã®ãããªã¯ã¨ãªã追å ãããããã«6ã¤ã®ãã©ã¡ã¼ã¿ãSpanã«è¿½å ããã¾ãã
ãã£ã¦å¤æ°ã®ãã©ã¡ã¼ã¿ãæ±ãå ´åãXSAM/otelsqlãgo.nhat.io/otelsqlã§ãã©ã¡ã¼ã¿ãSpanã«è¿½å ããããã«ãã¦ããã¨ãé常ã«å¤ãã®å±æ§ãSpanã«è¿½å ããã¦ãã¾ãã¾ãããããé²ãããã«ã¯ã AttributeGetter ã WithQuery ã§æ¸¡ã颿°ã®ä¸ã§è¨é²ãããã©ã¡ã¼ã¿ã®æ°ãå¶éãããªã©ã®å·¥å¤«ãå¿
è¦ã§ãã
sqlxã® sqlx.In ã使ãå ´å
sqlx.In ã使ãã¨ãSQLã¯ã¨ãªã®ä¸ã« ? ãã¬ã¼ã¹ãã«ããè¤æ°å«ã¾ããå ´åã«ãããå±éãã¦ããã¾ããä¾ãã°ä»¥ä¸ã®ãããªã³ã¼ãã§ãã
query, args, err := sqlx.In("SELECT id, title, description, created_at FROM todos WHERE id IN (?) ORDER BY created_at DESC", ids) if err != nil { return nil, fmt.Errorf("failed to build IN query: %w", err) } var todos []Todo if err := tx.SelectContext(ctx, &todos, query, args...); err != nil { return nil, fmt.Errorf("failed to get todos: %w", err) }
ãã®å ´å sqlx.In 㯠ids ã®è¦ç´ æ°ã«å¿ã㦠? ãã¬ã¼ã¹ãã«ããå±éãã args ã«ãã®å¤ãè¨å®ãã¾ããä¾ãã° ids ã [1, 2, 3] ã§ããã°ã query 㯠SELECT id, title, description, created_at FROM todos WHERE id IN (?,?,?) ORDER BY created_at DESC ã¨ãªãã args 㯠1, 2, 3 ã¨ãªãã¾ãã
ãããã¤ã³ãµã¼ãããå ´åã¨åæ§ã«ã sqlx.In ã使ãã±ã¼ã¹ã§ã夿°ã®ãã©ã¡ã¼ã¿ãspanã«è¿½å ããã¦ãã¾ãå¯è½æ§ããããã¨ã«æ³¨æãå¿
è¦ã§ãã
ã¾ã¨ã
CloudPlatformé¨ã§ã¤ã³ã¿ã¼ã³ã·ãããéå¬ããå¦çã®æ¹ã«Goè¨èªã®OpenTelemetryè¨è£ ã©ã¤ãã©ãªãæ¯è¼æ¤è¨ãã¦ããã ãã¾ããããã®ææãå ã«ãæçµçã«æã ã®ãã¼ãºã«æãåè´ãã¦ããã¨èããããã©ã¤ãã©ãªãæ¡ç¨ãããã¨ã¨ãã¾ããã
ãã®è¨äºã§ã¯æ¬çããå¤ãã¦ãã¾ãããç´¹ä»ãåãã¦ãã¾ããããæ³ç°ããã«ã¯å®éã«ç¨¼åãã¦ããé«ãã©ãã£ãã¯ãªãµã¼ãã¹ã«å¯¾ãã¦è¨è£ ãè¡ã£ã¦ããã ã大å¤å©ããã¾ããã
CloudPlatformé¨ã§ã¯å¼ãç¶ãéç¨ãããããµã¼ãã¹ã®å®ç¾ãç®æãããªãã¶ã¼ãããªãã£ã®åä¸ã«ãç©æ¥µçã«åãçµãã§ããã¾ããèå³ãããã°æ¯é以ä¸ã®æ¡ç¨æ å ±ãã覧ãã ããã
ã¾ããæ¨å¹´ã®ã¤ã³ã¿ã¼ã³ã·ããã®æ§åãåãçµãã 課é¡ã«ã¤ãã¦ã¯ä»¥ä¸ããã覧é ãã¾ãããèå³ããã°æ¯éã覧ãã ããã
- nginxのproxy_cache_lockと謎の500ms - Cybozu Inside Out | サイボウズエンジニアのブログ
- Cloudflare の新しいロードバランサ Pingora を試してみる - Cybozu Inside Out | サイボウズエンジニアのブログ
*1:
*2:eBPFãã¼ã¹ã®èªåè¨è£ ãåå¨ãã¦ãã¾ãããæã ã®ã¯ã©ã¹ã¿ã§ã¯æ¨©éçã«å°å ¥ããã®ãé£ãããã¨ããã¾ã çºå±éä¸ã§ããå®å®æ§ã«æ¬ ãããã¨ããä»åã¯å¯¾è±¡å¤ã¨ãã¦ãã¾ã
*3:ãã«ãæã«è¨è£ ã追å ãããã¼ã«ãåå¨ãã¦ãã¾ãããå ¸åçãªã³ã¼ã以å¤ã§ã¯ãã¾ããã¾ãåä½ããªãã£ããã¨ããæç¤ºçã«å®è£ ããæ¹éã¨ãã¦ãã¾ã
*4:
*5:å®éã«ã¯ OTEL_SEMCONV_STABILITY_OPT_IN ã¨ããç°å¢å¤æ°ã§ååãå¶å¾¡ã§ãã¾ãã https://pkg.go.dev/github.com/XSAM/otelsql#readme-trace-semantic-convention-stability
*6:https://github.com/go-sql-driver/mysql/issues/561
*7:semconvã®ãã¼ã¸ã§ã³æ´æ°æã«ã¯ãã©ã¡ã¼ã¿ã«é¢ãã仿§å¤æ´ãªã©ãå«ã¾ãã¦ãããã¨ããããç§»è¡ææã«ã¯ä¸¡æ¹ã®å¤ãåºåãã¦ç§»è¡æéãè¨ããããããã«ããã¹ãã§ããã¨ãããã¨ã決ãããã¦ãã¾ããä»åç¨ãã¦ãã database ã«é¢ãã夿´ãããããã®ç°å¢å¤æ°ããµãã¼ãããã¦ãããã¨ã§æ§æ¥ã®semconvã使ã£ã¦ããã·ã¹ãã ã«ããæ°ããsemconvã使ã£ã¦ããã·ã¹ãã ã«ã対å¿ã§ããããã«ãªãã¾ã